创建,添加sdram

This commit is contained in:
sc committed 2025-11-16 15:44:34 +08:00
commit 90c74bc31a
2944 files changed
+1430509

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Split('''
cache.c
cpuport.c
gtimer.c
mmu.c
pmu.c
stack.c
backtrace.c
''')
CPPPATH = [cwd]
if GetDepend('RT_USING_GIC_V2'):
src += ['interrupt.c']
src += ['gic.c']
src += ['trap.c']
if GetDepend('RT_USING_GIC_V3'):
src += ['interrupt.c']
src += ['gicv3.c']
src += ['trap.c']
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')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2023 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-12 WangXiaoyao the first version
*/
#ifndef __ASM_GENERIC_H__
#define __ASM_GENERIC_H__
#define START_POINT(funcname) \
.type funcname, %function; \
.global funcname; \
funcname: \
.cfi_sections .debug_frame, .eh_frame; \
.cfi_startproc; \
.cfi_undefined lr
#define START_POINT_END(name) \
.cfi_endproc; \
.size name, .-name;
#endif /* __ASM_GENERIC_H__ */
+543
View File
@@ -0,0 +1,543 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 Jesven the first version
*/
#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", frame.pc);
#endif
LOG_D("pc = %08x, sp = %08x", frame.pc, frame.sp);
while (1)
{
int urc;
urc = unwind_frame(&frame, &origin_idx, exidx_start, exidx_end);
if (urc < 0)
break;
//dump_backtrace_entry(where, frame.pc, frame.sp - 4);
#ifndef RT_BACKTRACE_FUNCTION_NAME
rt_kprintf(" %08x", frame.pc);
#endif
LOG_D("from: pc = %08x, frame = %08x", frame.pc, frame.sp - 4);
}
rt_kprintf("\n");
}
extern const struct unwind_idx __exidx_start[];
extern const struct unwind_idx __exidx_end[];
void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj)
{
struct pt_regs e_regs;
e_regs.ARM_fp = regs->fp;
e_regs.ARM_sp = regs->sp;
e_regs.ARM_lr = regs->lr;
e_regs.ARM_pc = regs->pc - pc_adj;
#ifdef RT_USING_SMART
if (!lwp_user_accessable((void *)e_regs.ARM_pc, sizeof (void *)))
{
e_regs.ARM_pc = regs->lr - sizeof(void *);
}
#endif
rt_kprintf("backtrace:\n");
unwind_backtrace(&e_regs, __exidx_start, __exidx_end);
}
rt_err_t rt_backtrace(void)
{
struct rt_hw_exp_stack regs;
asm volatile ("mov %0, fp":"=r"(regs.fp));
asm volatile ("mov %0, sp":"=r"(regs.sp));
asm volatile ("mov %0, lr":"=r"(regs.lr));
asm volatile ("mov %0, pc":"=r"(regs.pc));
rt_unwind(&regs, 8);
return RT_EOK;
}
+83
View File
@@ -0,0 +1,83 @@
#ifndef __BACKTRACE_H
#define __BACKTRACE_H
#ifndef __ASSEMBLY__
#include <rtthread.h>
#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);
#endif /* !__ASSEMBLY__ */
#endif /* __BACKTRACE_H */
+155
View File
@@ -0,0 +1,155 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 quanzhao the first version
*/
#include <rthw.h>
#include <rtdef.h>
rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
{
rt_uint32_t ctr;
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
return 4 << (ctr & 0xF);
}
rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
{
rt_uint32_t ctr;
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
return 4 << ((ctr >> 16) & 0xF);
}
void rt_hw_cpu_icache_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_icache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r"(start_addr)); /* icimvau */
start_addr += line_size;
}
asm volatile ("dsb\n\tisb":::"memory");
}
void rt_hw_cpu_dcache_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_inv_range(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t)addr + size;
asm volatile ("dmb":::"memory");
if ((start_addr & (line_size - 1)) != 0)
{
start_addr &= ~(line_size - 1);
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
start_addr += line_size;
asm volatile ("dsb":::"memory");
}
if ((end_addr & (line_size - 1)) != 0)
{
end_addr &= ~(line_size - 1);
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(end_addr));
asm volatile ("dsb":::"memory");
}
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_clean(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
{
rt_hw_cpu_icache_invalidate(addr, size);
}
}
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_FLUSH)
{
rt_hw_cpu_dcache_clean(addr, size);
}
else if (ops == RT_HW_CACHE_INVALIDATE)
{
rt_hw_cpu_dcache_invalidate(addr, size);
}
}
rt_base_t rt_hw_cpu_icache_status(void)
{
return 0;
}
rt_base_t rt_hw_cpu_dcache_status(void)
{
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 quanzhao the first version
*/
#ifndef __CACHE_H__
#define __CACHE_H__
void rt_hw_cpu_icache_invalidate(void *addr, int size);
void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, int size);
static inline void rt_hw_icache_invalidate_all(void)
{
__asm__ volatile("mcr p15, 0, %0, c7, c5, 0"::"r"(0ul));
}
#endif /* __CACHE_H__ */
+268
View File
@@ -0,0 +1,268 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
#include "rtconfig.h"
.section .text, "ax"
#ifdef RT_USING_SMP
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
#endif
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
cpsid i
bx lr
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr, r0
bx lr
/*
* void rt_hw_context_switch_to(rt_uint32 to, struct rt_thread *to_thread);
* r0 --> to (thread stack)
* r1 --> to_thread
*/
.globl rt_hw_context_switch_to
rt_hw_context_switch_to:
clrex
ldr sp, [r0] @ get new task stack pointer
#ifdef RT_USING_SMP
mov r0, r1
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_restore
#endif
#else
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#endif /*RT_USING_SMP*/
b rt_hw_context_switch_exit
.section .bss.share.isr
_guest_switch_lvl:
.word 0
.globl vmm_virq_update
.section .text.isr, "ax"
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to, struct rt_thread *to_thread);
* r0 --> from (from_thread stack)
* r1 --> to (to_thread stack)
* r2 --> to_thread
*/
.globl rt_hw_context_switch
rt_hw_context_switch:
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_SMART
stmfd sp, {r13, r14}^ @ push usr_sp usr_lr
sub sp, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb sp!, {d0-d15}
vstmdb sp!, {d16-d31}
vmrs r5, fpscr
stmfd sp!, {r5}
1:
stmfd sp!, {r6}
#endif
str sp, [r0] @ store sp in preempted tasks TCB
ldr sp, [r1] @ get new task stack pointer
#ifdef RT_USING_SMP
mov r0, r2
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_restore
#endif
#else
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#endif /*RT_USING_SMP*/
b rt_hw_context_switch_exit
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
*/
.equ Mode_USR, 0x10
.equ Mode_FIQ, 0x11
.equ Mode_IRQ, 0x12
.equ Mode_SVC, 0x13
.equ Mode_ABT, 0x17
.equ Mode_UND, 0x1B
.equ Mode_SYS, 0x1F
.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled
.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
.globl rt_hw_context_switch_interrupt
rt_hw_context_switch_interrupt:
clrex
#ifdef RT_USING_SMP
/* r0 :svc_mod context
* r1 :addr of from_thread's sp
* r2 :addr of to_thread's sp
* r3 :to_thread's tcb
*/
#ifdef RT_USING_SMART
push {r0 - r3, lr}
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_save
#endif
pop {r0 - r3, lr}
#endif
str r0, [r1]
ldr sp, [r2]
mov r0, r3
#ifdef RT_USING_SMART
mov r4, r0
#endif
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
mov r0, r4
bl lwp_user_setting_restore
#endif
b rt_hw_context_switch_exit
#else /*RT_USING_SMP*/
/* r0 :addr of from_thread's sp
* r1 :addr of to_thread's sp
* r2 :from_thread's tcb
* r3 :to_thread's tcb
*/
#ifdef RT_USING_SMART
/* now to_thread(r3) not used */
ldr ip, =rt_thread_switch_interrupt_flag
ldr r3, [ip]
cmp r3, #1
beq _reswitch
ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r3]
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [ip]
#ifdef RT_USING_SMART
push {r1, lr}
mov r0, r2
bl lwp_user_setting_save
pop {r1, lr}
#endif
_reswitch:
ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [ip]
bx lr
#else
/* now from_thread(r2) to_thread(r3) not used */
ldr ip, =rt_thread_switch_interrupt_flag
ldr r3, [ip]
cmp r3, #1
beq _reswitch
ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r3]
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [ip]
_reswitch:
ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [ip]
bx lr
#endif
#endif /*RT_USING_SMP*/
.global rt_hw_context_switch_exit
rt_hw_context_switch_exit:
#ifdef RT_USING_SMP
#ifdef RT_USING_SIGNALS
mov r0, sp
cps #Mode_IRQ
bl rt_signal_check
cps #Mode_SVC
mov sp, r0
#endif
#endif
#ifdef RT_USING_FPU
/* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq 1f
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d16-d31}
vldmia sp!, {d0-d15}
1:
#endif
#ifdef RT_USING_SMART
ldmfd sp, {r13, r14}^ /* usr_sp, usr_lr */
add sp, #8
#endif
ldmfd sp!, {r1}
msr spsr_cxsf, r1 /* original mode */
#ifdef RT_USING_SMART
and r1, #0x1f
cmp r1, #0x10
bne 1f
ldmfd sp!, {r0-r12,lr}
ldmfd sp!, {lr}
b arch_ret_to_user
1:
#endif
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
#ifdef RT_USING_FPU
.global set_fpexc
set_fpexc:
vmsr fpexc, r0
bx lr
#endif
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-03-25 quanzhao the first version
*/
#ifndef __CP15_H__
#define __CP15_H__
#define __get_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
#define __set_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
#define __get_cp64(cp, op1, Rt, CRm) __asm__ volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
#define __set_cp64(cp, op1, Rt, CRm) __asm__ volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
int rt_hw_cpu_id(void);
void rt_cpu_mmu_disable(void);
void rt_cpu_mmu_enable(void);
void rt_cpu_tlb_set(volatile unsigned long*);
void rt_cpu_dcache_clean_flush(void);
void rt_cpu_icache_flush(void);
void rt_cpu_vector_set_base(unsigned int addr);
#endif
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
.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:
push {r4-r11}
dmb
mrc p15, #1, r0, c0, c0, #1 @ read clid register
ands r3, r0, #0x7000000 @ get level of coherency
mov r3, r3, lsr #23
beq finished
mov r10, #0
loop1:
add r2, r10, r10, lsr #1
mov r1, r0, lsr r2
and r1, r1, #7
cmp r1, #2
blt skip
mcr p15, #2, r10, c0, c0, #0
isb
mrc p15, #1, r1, c0, c0, #0
and r2, r1, #7
add r2, r2, #4
ldr r4, _FLD_MAX_WAY
ands r4, r4, r1, lsr #3
clz r5, r4
ldr r7, _FLD_MAX_IDX
ands r7, r7, r1, lsr #13
loop2:
mov r9, r4
loop3:
orr r11, r10, r9, lsl r5
orr r11, r11, r7, lsl r2
mcr p15, #0, r11, c7, c14, #2
subs r9, r9, #1
bge loop3
subs r7, r7, #1
bge loop2
skip:
add r10, r10, #2
cmp r3, r10
bgt loop1
finished:
dsb
isb
pop {r4-r11}
bx lr
.globl rt_cpu_icache_flush
rt_cpu_icache_flush:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
dsb
isb
bx lr
.globl rt_hw_cpu_dcache_disable
rt_hw_cpu_dcache_disable:
push {r4-r11, lr}
bl rt_cpu_dcache_clean_flush
mrc p15, #0, r0, c1, c0, #0
bic r0, r0, #0x00000004
mcr p15, #0, r0, c1, c0, #0
pop {r4-r11, lr}
bx lr
.globl rt_hw_cpu_icache_disable
rt_hw_cpu_icache_disable:
mrc p15, #0, r0, c1, c0, #0
bic r0, r0, #0x00001000
mcr p15, #0, r0, c1, c0, #0
bx lr
.globl rt_cpu_mmu_disable
rt_cpu_mmu_disable:
mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb
mrc p15, #0, r0, c1, c0, #0
bic r0, r0, #1
mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit
dsb
bx lr
.globl rt_cpu_mmu_enable
rt_cpu_mmu_enable:
mrc p15, #0, r0, c1, c0, #0
orr r0, r0, #0x001
mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit
dsb
bx lr
.globl rt_cpu_tlb_set
rt_cpu_tlb_set:
mcr p15, #0, r0, c2, c0, #0
dmb
bx lr
+113
View File
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-15 Bernard first version
* 2018-11-22 Jesven add rt_hw_cpu_id()
*/
#include <rthw.h>
#include <rtthread.h>
#include <board.h>
rt_weak 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;
}
#ifdef RT_USING_SMP
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
{
lock->slock = 0;
}
void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
{
unsigned long tmp;
unsigned long newval;
rt_hw_spinlock_t lockval;
__asm__ __volatile__(
"pld [%0]"
::"r"(&lock->slock)
);
__asm__ __volatile__(
"1: ldrex %0, [%3]\n"
" add %1, %0, %4\n"
" strex %2, %1, [%3]\n"
" teq %2, #0\n"
" bne 1b"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << 16)
: "cc");
while (lockval.tickets.next != lockval.tickets.owner) {
__asm__ __volatile__("wfe":::"memory");
lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner);
}
__asm__ volatile ("dmb":::"memory");
}
void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
{
__asm__ volatile ("dmb":::"memory");
lock->tickets.owner++;
__asm__ volatile ("dsb ishst\nsev":::"memory");
}
#endif /*RT_USING_SMP*/
/**
* @addtogroup ARM CPU
*/
/*@{*/
/** shutdown CPU */
void rt_hw_cpu_shutdown(void)
{
rt_base_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
while (level)
{
RT_ASSERT(0);
}
}
#ifdef RT_USING_CPU_FFS
/**
* This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @return return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
int __rt_ffs(int value)
{
return __builtin_ffs(value);
}
#endif
rt_bool_t rt_hw_interrupt_is_disabled(void)
{
int rc;
__asm__ volatile("mrs %0, cpsr" : "=r" (rc));
return !!(rc & 0x80);
}
/*@}*/
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef CPUPORT_H__
#define CPUPORT_H__
#include <rtcompiler.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)
#ifdef RT_USING_SMP
typedef union {
unsigned long slock;
struct __arch_tickets {
unsigned short owner;
unsigned short next;
} tickets;
} rt_hw_spinlock_t;
#endif
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");
}
void _thread_start(void);
#endif /*CPUPORT_H__*/
+499
View File
@@ -0,0 +1,499 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
*/
#include <rthw.h>
#include <rtthread.h>
#include "gic.h"
#include "cp15.h"
struct arm_gic
{
rt_uint32_t offset; /* the first interrupt index in the vector table */
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
};
/* 'ARM_GIC_MAX_NR' is the number of cores */
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
static unsigned int _gic_max_irq;
int arm_gic_get_active_irq(rt_uint32_t index)
{
int irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base);
irq += _gic_table[index].offset;
return irq;
}
void arm_gic_ack(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
}
void arm_gic_mask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
void arm_gic_umask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t pend;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
else
{
/* INTID 0-15 Software Generated Interrupt */
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
/* No CPU identification offered */
if (pend != 0U)
{
pend = 1U;
}
else
{
pend = 0U;
}
}
return (pend);
}
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
}
else
{
/* INTID 0-15 Software Generated Interrupt */
/* Forward the interrupt to the CPU interface that requested it */
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
}
}
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
mask = 1U << (irq % 32U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
else
{
mask = 1U << ((irq % 4U) * 8U);
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
{
rt_uint32_t icfgr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
shift = (irq % 16U) << 1U;
icfgr &= (~(3U << shift));
icfgr |= (config << (shift + 1));
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
}
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
}
void arm_gic_clear_active(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
/* Set up the cpu mask for the specific interrupt */
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
{
rt_uint32_t old_tgt;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
old_tgt |= cpumask << ((irq % 4U)*8U);
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
}
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
/* set priority mask */
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
}
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
{
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
}
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
{
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
}
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
{
rt_uint32_t pending;
rt_uint32_t active;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
return ((active << 1U) | pending);
}
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
}
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
}
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
{
rt_uint32_t igroupr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(group <= 1U);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
shift = (irq % 32U);
igroupr &= (~(1U << shift));
igroupr |= ( (group & 0x1U) << shift);
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
}
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
{
unsigned int gic_type, i;
rt_uint32_t cpumask = 1U << 0U;
RT_ASSERT(index < ARM_GIC_MAX_NR);
_gic_table[index].dist_hw_base = dist_base;
_gic_table[index].offset = irq_start;
/* Find out how many interrupts are supported. */
gic_type = GIC_DIST_TYPE(dist_base);
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
/*
* The GIC only supports up to 1020 interrupt sources.
* Limit this to either the architected maximum, or the
* platform maximum.
*/
if (_gic_max_irq > 1020U)
_gic_max_irq = 1020U;
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
_gic_max_irq = ARM_GIC_NR_IRQS;
cpumask |= cpumask << 8U;
cpumask |= cpumask << 16U;
cpumask |= cpumask << 24U;
GIC_DIST_CTRL(dist_base) = 0x0U;
/* Set all global interrupts to be level triggered, active low. */
for (i = 32U; i < _gic_max_irq; i += 16U)
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
/* Set all global interrupts to this CPU only. */
for (i = 32U; i < _gic_max_irq; i += 4U)
GIC_DIST_TARGET(dist_base, i) = cpumask;
/* Set priority on all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 4U)
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
/* Disable all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
#if 0
/* All interrupts defaults to IGROUP1(IRQ). */
for (i = 0; i < _gic_max_irq; i += 32)
GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
#endif
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_IGROUP(dist_base, i) = 0U;
/* Enable group0 and group1 interrupt forwarding. */
GIC_DIST_CTRL(dist_base) = 0x01U;
return 0;
}
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
if (!_gic_table[index].cpu_hw_base)
{
_gic_table[index].cpu_hw_base = cpu_base;
}
cpu_base = _gic_table[index].cpu_hw_base;
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
/* Enable CPU interrupt */
GIC_CPU_CTRL(cpu_base) = 0x01U;
return 0;
}
void arm_gic_dump_type(rt_uint32_t index)
{
unsigned int gic_type;
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
_gic_table[index].dist_hw_base,
_gic_max_irq,
gic_type & (1U << 10U) ? "has" : "no",
gic_type);
}
void arm_gic_dump(rt_uint32_t index)
{
unsigned int i, k;
k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
rt_kprintf("--- hw mask ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw pending ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw active ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n");
}
long gic_dump(void)
{
arm_gic_dump_type(0);
arm_gic_dump(0);
return 0;
}
MSH_CMD_EXPORT(gic_dump, show gic status);
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#ifndef __GIC_H__
#define __GIC_H__
#include <rthw.h>
#include <board.h>
int arm_gic_get_active_irq(rt_uint32_t index);
void arm_gic_ack(rt_uint32_t index, int irq);
void arm_gic_mask(rt_uint32_t index, int irq);
void arm_gic_umask(rt_uint32_t index, int irq);
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
void arm_gic_clear_active(rt_uint32_t index, int irq);
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list);
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base);
void arm_gic_dump_type(rt_uint32_t index);
void arm_gic_dump(rt_uint32_t index);
#endif
+708
View File
@@ -0,0 +1,708 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
*/
#include <rthw.h>
#include <rtthread.h>
#include "gicv3.h"
#include "cp15.h"
#ifndef RT_CPUS_NR
#define RT_CPUS_NR 1
#endif
struct arm_gic_v3
{
rt_uint32_t offset; /* the first interrupt index in the vector table */
rt_uint32_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
rt_uint32_t cpu_hw_base[RT_CPUS_NR]; /* the base addrees of the gic cpu interface */
};
/* 'ARM_GIC_MAX_NR' is the number of cores */
static struct arm_gic_v3 _gic_table[ARM_GIC_MAX_NR];
static unsigned int _gic_max_irq;
/**
* @name: arm_gic_cpumask_to_affval
* @msg:
* @in param cpu_mask:
* @out param cluster_id: aff1 [0:7],aff2 [8:15],aff3 [16:23]
* @out param target_list: Target List. The set of PEs for which SGI interrupts will be generated. Each bit corresponds to the
* PE within a cluster with an Affinity 0 value equal to the bit number.
* @return {rt_uint32_t} 0 is finish , 1 is data valid
*/
rt_weak rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list)
{
return 0;
}
rt_weak rt_uint64_t get_main_cpu_affval(void)
{
return 0;
}
int arm_gic_get_active_irq(rt_uint32_t index)
{
int irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
__get_gicv3_reg(ICC_IAR1, irq);
irq = (irq & 0x1FFFFFF) + _gic_table[index].offset;
return irq;
}
void arm_gic_ack(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(irq >= 0U);
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_gicv3_reg(ICC_EOIR1, irq);
}
void arm_gic_mask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
}
else
{
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_umask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
}
else
{
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
}
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t pend;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
else
{
/* INTID 0-15 Software Generated Interrupt */
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
/* No CPU identification offered */
if (pend != 0U)
{
pend = 1U;
}
else
{
pend = 0U;
}
}
return (pend);
}
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
}
else
{
/* INTID 0-15 Software Generated Interrupt */
/* Forward the interrupt to the CPU interface that requested it */
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
}
}
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
mask = 1U << (irq % 32U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
else
{
mask = 1U << ((irq % 4U) * 8U);
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
{
rt_uint32_t icfgr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
shift = (irq % 16U) << 1U;
icfgr &= (~(3U << shift));
icfgr |= (config << (shift + 1));
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
}
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
}
void arm_gic_clear_active(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
/* Set up the cpu mask for the specific interrupt */
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
{
rt_uint32_t old_tgt;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
old_tgt &= ~(0x0FFUL << ((irq % 4U) * 8U));
old_tgt |= cpumask << ((irq % 4U) * 8U);
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
}
else
{
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
else
{
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
}
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
value &= 0xFFUL;
/* set priority mask */
__set_gicv3_reg(ICC_SRE, value);
__asm__ volatile ("isb 0xF"::
:"memory");
}
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
rt_uint32_t value;
__get_gicv3_reg(ICC_SRE, value);
return value;
}
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
priority &= 0xFFUL;
/* set priority mask */
__set_gicv3_reg(ICC_PMR, priority);
}
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
rt_uint32_t priority;
__get_gicv3_reg(ICC_PMR, priority);
return priority;
}
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
{
index = index;
binary_point &= 0x7U;
__set_gicv3_reg(ICC_BPR1, binary_point);
}
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
{
rt_uint32_t binary_point;
index = index;
__get_gicv3_reg(ICC_BPR1, binary_point);
return binary_point;
}
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
{
rt_uint32_t pending;
rt_uint32_t active;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
return ((active << 1U) | pending);
}
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode)
{
rt_uint64_t sgi_val;
if (routing_mode)
{
sgi_val = (1ULL << 40) | ((irq & 0x0FULL) << 24); //Interrupts routed to all PEs in the system, excluding "self".
/* Write the ICC_SGI1R registers */
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_cp64(15, 0, sgi_val, 12);
__asm__ volatile("isb 0xF" ::
: "memory");
}
else
{
rt_uint32_t cluster_id, target_list;
while (arm_gic_cpumask_to_affval(&cpu_mask, &cluster_id, &target_list))
{
sgi_val = ((irq & 0x0FULL) << 24 |
target_list |
((cluster_id >> 8) & 0xFFULL) << GIC_RSGI_AFF1_OFFSET |
((cluster_id >> 16) & 0xFFULL) << GIC_RSGI_AFF2_OFFSET |
((cluster_id >> 24) & 0xFFull) << GIC_RSGI_AFF3_OFFSET);
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_cp64(15, 0, sgi_val, 12);
__asm__ volatile("isb 0xF" ::
: "memory");
}
}
}
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
{
rt_uint32_t irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
index = index;
__get_gicv3_reg(ICC_HPPIR1, irq);
return irq;
}
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
{
rt_uint32_t igroupr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(group <= 1U);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
shift = (irq % 32U);
igroupr &= (~(1U << shift));
igroupr |= ((group & 0x1U) << shift);
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
}
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
static int arm_gicv3_wait_rwp(rt_uint32_t index, rt_uint32_t irq)
{
rt_uint32_t rwp_bit;
rt_uint32_t base;
RT_ASSERT(index < ARM_GIC_MAX_NR);
if (irq < 32u)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
base = _gic_table[index].redist_hw_base[cpu_id];
rwp_bit = GICR_CTLR_RWP;
}
else
{
base = _gic_table[index].dist_hw_base;
rwp_bit = GICD_CTLR_RWP;
}
while (__REG32(base) & rwp_bit)
{
;
}
return 0;
}
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
{
rt_uint64_t cpu0_affval;
unsigned int gic_type, i;
RT_ASSERT(index < ARM_GIC_MAX_NR);
_gic_table[index].dist_hw_base = dist_base;
_gic_table[index].offset = irq_start;
/* Find out how many interrupts are supported. */
gic_type = GIC_DIST_TYPE(dist_base);
_gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;
/*
* The GIC only supports up to 1020 interrupt sources.
* Limit this to either the architected maximum, or the
* platform maximum.
*/
if (_gic_max_irq > 1020U)
_gic_max_irq = 1020U;
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
_gic_max_irq = ARM_GIC_NR_IRQS;
GIC_DIST_CTRL(dist_base) = 0x0U;
/* Wait for register write pending */
arm_gicv3_wait_rwp(0, 32);
/* Set all global interrupts to be level triggered, active low. */
for (i = 32U; i < _gic_max_irq; i += 16U)
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
arm_gicv3_wait_rwp(0, 32);
cpu0_affval = get_main_cpu_affval();
/* Set all global interrupts to this CPU only. */
for (i = 32U; i < _gic_max_irq; i++)
{
GIC_DIST_IROUTER_LOW(dist_base, i) = cpu0_affval;
GIC_DIST_IROUTER_HIGH(dist_base, i) = cpu0_affval >> 32;
}
arm_gicv3_wait_rwp(0, 32);
/* Set priority on spi interrupts. */
for (i = 32U; i < _gic_max_irq; i += 4U)
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
arm_gicv3_wait_rwp(0, 32);
/* Disable all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 32U)
{
GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffffU;
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
}
arm_gicv3_wait_rwp(0, 32);
/* All interrupts defaults to IGROUP1(IRQ). */
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_IGROUP(dist_base, i) = 0xffffffffU;
arm_gicv3_wait_rwp(0, 32);
/*
The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
If affinity routing is not enabled, GICv3 can be configured for legacy operation.
Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
*/
GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;
return 0;
}
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
_gic_table[index].redist_hw_base[cpu_id] = redist_addr;
return 0;
}
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
_gic_table[index].cpu_hw_base[cpu_id] = interface_addr;
return 0;
}
int arm_gic_redist_init(rt_uint32_t index)
{
unsigned int i;
rt_uint32_t base;
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
base = _gic_table[index].redist_hw_base[cpu_id];
/* redistributor enable */
GIC_RDIST_WAKER(base) &= ~(1U << 1);
while (GIC_RDIST_WAKER(base) & (1 << 2))
{
;
}
/* Disable all sgi and ppi interrupt */
GIC_RDISTSGI_ICENABLER0(base) = 0xFFFFFFFF;
arm_gicv3_wait_rwp(0, 0);
/* Clear all inetrrupt pending */
GIC_RDISTSGI_ICPENDR0(base) = 0xFFFFFFFF;
/* the corresponding interrupt is Group 1 or Non-secure Group 1. */
GIC_RDISTSGI_IGROUPR0(base, 0) = 0xFFFFFFFF;
GIC_RDISTSGI_IGRPMODR0(base, 0) = 0xFFFFFFFF;
/* Configure default priorities for SGI 0:15 and PPI 16:31. */
for (i = 0; i < 32; i += 4)
{
GIC_RDISTSGI_IPRIORITYR(base, i) = 0xa0a0a0a0U;
}
/* Trigger level for PPI interrupts*/
GIC_RDISTSGI_ICFGR1(base) = 0x0U; // PPI is level-sensitive.
return 0;
}
int arm_gic_cpu_init(rt_uint32_t index)
{
rt_uint32_t value;
RT_ASSERT(index < ARM_GIC_MAX_NR);
value = arm_gic_get_system_register_enable_mask(index);
value |= (1U << 0);
arm_gic_set_system_register_enable_mask(index, value);
__set_gicv3_reg(ICC_CTLR, 0);
arm_gic_set_interface_prior_mask(index, 0xFFU);
/* Enable group1 interrupt */
value = 0x1U;
__set_gicv3_reg(ICC_IGRPEN1, value);
arm_gic_set_binary_point(0, 0);
/* ICC_BPR0_EL1 determines the preemption group for both
Group 0 and Group 1 interrupts.
*/
value = 0x1U;
__set_gicv3_reg(ICC_CTLR, value);
return 0;
}
#ifdef RT_USING_SMP
void arm_gic_secondary_cpu_init(void)
{
arm_gic_redist_init(0);
arm_gic_cpu_init(0);
}
#endif
void arm_gic_dump_type(rt_uint32_t index)
{
unsigned int gic_type;
gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n",
(GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
_gic_table[index].dist_hw_base,
_gic_max_irq,
gic_type & (1U << 10U) ? "has" : "no",
gic_type);
}
void arm_gic_dump(rt_uint32_t index)
{
unsigned int i, k;
k = arm_gic_get_high_pending_irq(0);
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
rt_kprintf("--- hw mask ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw pending ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw active ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n");
}
long gic_dump(void)
{
arm_gic_dump_type(0);
arm_gic_dump(0);
return 0;
}
MSH_CMD_EXPORT(gic_dump, show gic status);
+194
View File
@@ -0,0 +1,194 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#ifndef __GIC_V3_H__
#define __GIC_V3_H__
#include <rthw.h>
#include <board.h>
#define __get_gicv3_reg(CR, Rt) __asm__ volatile("MRC " CR \
: "=r"(Rt) \
: \
: "memory")
#define __set_gicv3_reg(CR, Rt) __asm__ volatile("MCR " CR \
: \
: "r"(Rt) \
: "memory")
/* AArch32 System register interface to GICv3 */
#define ICC_IAR0 "p15, 0, %0, c12, c8, 0"
#define ICC_IAR1 "p15, 0, %0, c12, c12, 0"
#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1"
#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1"
#define ICC_HPPIR0 "p15, 0, %0, c12, c8, 2"
#define ICC_HPPIR1 "p15, 0, %0, c12, c12, 2"
#define ICC_BPR0 "p15, 0, %0, c12, c8, 3"
#define ICC_BPR1 "p15, 0, %0, c12, c12, 3"
#define ICC_DIR "p15, 0, %0, c12, c11, 1"
#define ICC_PMR "p15, 0, %0, c4, c6, 0"
#define ICC_RPR "p15, 0, %0, c12, c11, 3"
#define ICC_CTLR "p15, 0, %0, c12, c12, 4"
#define ICC_MCTLR "p15, 6, %0, c12, c12, 4"
#define ICC_SRE "p15, 0, %0, c12, c12, 5"
#define ICC_HSRE "p15, 4, %0, c12, c9, 5"
#define ICC_MSRE "p15, 6, %0, c12, c12, 5"
#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6"
#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7"
#define ICC_MGRPEN1 "p15, 6, %0, c12, c12, 7"
#define __REG32(x) (*((volatile unsigned int*)((rt_uint32_t)x)))
#define ROUTED_TO_ALL (1)
#define ROUTED_TO_SPEC (0)
/** Macro to access the Distributor Control Register (GICD_CTLR)
*/
#define GICD_CTLR_RWP (1<<31)
#define GICD_CTLR_E1NWF (1<<7)
#define GICD_CTLR_DS (1<<6)
#define GICD_CTLR_ARE_NS (1<<5)
#define GICD_CTLR_ARE_S (1<<4)
#define GICD_CTLR_ENGRP1S (1<<2)
#define GICD_CTLR_ENGRP1NS (1<<1)
#define GICD_CTLR_ENGRP0 (1<<0)
/** Macro to access the Redistributor Control Register (GICR_CTLR)
*/
#define GICR_CTLR_UWP (1<<31)
#define GICR_CTLR_DPG1S (1<<26)
#define GICR_CTLR_DPG1NS (1<<25)
#define GICR_CTLR_DPG0 (1<<24)
#define GICR_CTLR_RWP (1<<3)
#define GICR_CTLR_IR (1<<2)
#define GICR_CTLR_CES (1<<1)
#define GICR_CTLR_EnableLPI (1<<0)
/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
#define GIC_DIST_IROUTER_LOW(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U)
#define GIC_DIST_IROUTER_HIGH(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U + 4)
/* SGI base address is at 64K offset from Redistributor base address */
#define GIC_RSGI_OFFSET 0x10000
/** Macro to access the Generic Interrupt Controller Redistributor (GICD)
*/
#define GIC_RDIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_RDIST_IIDR(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_RDIST_TYPER(hw_base) __REG32((hw_base) + 0x008U)
#define GIC_RDIST_TSTATUSR(hw_base) __REG32((hw_base) + 0x010U)
#define GIC_RDIST_WAKER(hw_base) __REG32((hw_base) + 0x014U)
#define GIC_RDIST_SETLPIR(hw_base) __REG32((hw_base) + 0x040U)
#define GIC_RDIST_CLRLPIR(hw_base) __REG32((hw_base) + 0x048U)
#define GIC_RDIST_PROPBASER(hw_base) __REG32((hw_base) + 0x070U)
#define GIC_RDIST_PENDBASER(hw_base) __REG32((hw_base) + 0x078U)
#define GIC_RDIST_INVLPIR(hw_base) __REG32((hw_base) + 0x0A0U)
#define GIC_RDIST_INVALLR(hw_base) __REG32((hw_base) + 0x0B0U)
#define GIC_RDIST_SYNCR(hw_base) __REG32((hw_base) + 0x0C0U)
#define GIC_RDISTSGI_IGROUPR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n)*4U)
#define GIC_RDISTSGI_ISENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
#define GIC_RDISTSGI_ICENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
#define GIC_RDISTSGI_ISPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
#define GIC_RDISTSGI_ICPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
#define GIC_RDISTSGI_ISACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
#define GIC_RDISTSGI_ICACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
#define GIC_RDISTSGI_ICFGR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
#define GIC_RDISTSGI_ICFGR1(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n)*4)
#define GIC_RDISTSGI_NSACR(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)
#define GIC_RSGI_AFF1_OFFSET 16
#define GIC_RSGI_AFF2_OFFSET 32
#define GIC_RSGI_AFF3_OFFSET 48
rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list);
rt_uint64_t get_main_cpu_affval(void);
int arm_gic_get_active_irq(rt_uint32_t index);
void arm_gic_ack(rt_uint32_t index, int irq);
void arm_gic_mask(rt_uint32_t index, int irq);
void arm_gic_umask(rt_uint32_t index, int irq);
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
void arm_gic_clear_active(rt_uint32_t index, int irq);
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode);
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id);
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id);
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start);
int arm_gic_cpu_init(rt_uint32_t index);
int arm_gic_redist_init(rt_uint32_t index);
void arm_gic_dump_type(rt_uint32_t index);
void arm_gic_dump(rt_uint32_t index);
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value);
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index);
void arm_gic_secondary_cpu_init(void);
#endif
+179
View File
@@ -0,0 +1,179 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-30 huijie.feng first version
*/
#include "cp15.h"
#include <rtdef.h>
/** Set CNTFRQ
* This function assigns the given value to PL1 Physical Timer Counter Frequency Register (CNTFRQ).
* @param value: CNTFRQ Register value to set
*/
static inline void __set_cntfrq(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 0, 0);
}
/** Get CNTFRQ
* This function returns the value of the PL1 Physical Timer Counter Frequency Register (CNTFRQ).
* return CNTFRQ Register value
*/
static inline rt_uint32_t __get_cntfrq(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 0 , 0);
return result;
}
/** Set CNTP_TVAL
* This function assigns the given value to PL1 Physical Timer Value Register (CNTP_TVAL).
* param value: CNTP_TVAL Register value to set
*/
static inline void __set_cntp_tval(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 2, 0);
}
/** Get CNTP_TVAL
* This function returns the value of the PL1 Physical Timer Value Register (CNTP_TVAL).
* return CNTP_TVAL Register value
*/
static inline rt_uint32_t __get_cntp_tval(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 2, 0);
return result;
}
/** Get CNTPCT
* This function returns the value of the 64 bits PL1 Physical Count Register (CNTPCT).
* return CNTPCT Register value
*/
static inline rt_uint64_t __get_cntpct(void)
{
rt_uint64_t result;
__get_cp64(15, 0, result, 14);
return result;
}
/** Set CNTP_CVAL
* This function assigns the given value to 64bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
* param value: CNTP_CVAL Register value to set
*/
static inline void __set_cntp_cval(rt_uint64_t value)
{
__set_cp64(15, 2, value, 14);
}
/** Get CNTP_CVAL
* This function returns the value of the 64 bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
* return CNTP_CVAL Register value
*/
static inline rt_uint64_t __get_cntp_cval(void)
{
rt_uint64_t result;
__get_cp64(15, 2, result, 14);
return result;
}
/** Set CNTP_CTL
* This function assigns the given value to PL1 Physical Timer Control Register (CNTP_CTL).
* param value: CNTP_CTL Register value to set
*/
static inline void __set_cntp_ctl(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 2, 1);
}
/** Get CNTP_CTL register
* return CNTP_CTL Register value
*/
static inline rt_uint32_t __get_cntp_ctl(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 2, 1);
return result;
}
/** Configures the frequency the timer shall run at.
* param value The timer frequency in Hz.
*/
void gtimer_set_counter_frequency(rt_uint32_t value)
{
__set_cntfrq(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the frequency the timer shall run at.
* return timer frequency in Hz.
*/
rt_uint32_t gtimer_get_counter_frequency(void)
{
return(__get_cntfrq());
}
/** Sets the reset value of the timer.
* param value: The value the timer is loaded with.
*/
void gtimer_set_load_value(rt_uint32_t value)
{
__set_cntp_tval(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the current counter value.
* return Current counter value.
*/
rt_uint32_t gtimer_get_current_value(void)
{
return(__get_cntp_tval());
}
/** Get the current physical counter value.
* return Current physical counter value.
*/
rt_uint64_t gtimer_get_current_physical_value(void)
{
return(__get_cntpct());
}
/** Set the physical compare value.
* param value: New physical timer compare value.
*/
void gtimer_set_physical_compare_value(rt_uint64_t value)
{
__set_cntp_cval(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the physical compare value.
* return Physical compare value.
*/
rt_uint64_t gtimer_get_physical_compare_value(void)
{
return(__get_cntp_cval());
}
/** Configure the timer by setting the control value.
* param value: New timer control value.
*/
void gtimer_set_control(rt_uint32_t value)
{
__set_cntp_ctl(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the control value.
* return Control value.
*/
rt_uint32_t gtimer_get_control(void)
{
return(__get_cntp_ctl());
}
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-30 huijie.feng first version
*/
#ifndef __GTIMER_H__
#define __GTIMER_H__
#include <rtdef.h>
void gtimer_set_counter_frequency(rt_uint32_t value);
rt_uint32_t gtimer_get_counter_frequency(void);
void gtimer_set_load_value(rt_uint32_t value);
rt_uint32_t gtimer_get_current_value(void);
rt_uint64_t gtimer_get_current_physical_value(void);
void gtimer_set_physical_compare_value(rt_uint64_t value);
rt_uint64_t gtimer_get_physical_compare_value(void);
void gtimer_set_control(rt_uint32_t value);
rt_uint32_t gtimer_get_control(void);
#endif
+341
View File
@@ -0,0 +1,341 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard first version
* 2018-11-22 Jesven add smp support
*/
#include <rthw.h>
#include <rtthread.h>
#include "interrupt.h"
#ifdef RT_USING_GIC_V2
#include "gic.h"
#else
#include "gicv3.h"
#endif
/* exception and interrupt handler table */
struct rt_irq_desc isr_table[MAX_HANDLERS];
#ifndef RT_USING_SMP
/* Those varibles will be accessed in ISR, so we need to share them. */
rt_uint32_t rt_interrupt_from_thread = 0;
rt_uint32_t rt_interrupt_to_thread = 0;
rt_uint32_t rt_thread_switch_interrupt_flag = 0;
#ifdef RT_USING_HOOK
static void (*rt_interrupt_switch_hook)(void);
void rt_interrupt_switch_sethook(void (*hook)(void))
{
rt_interrupt_switch_hook = hook;
}
#endif
void rt_interrupt_hook(void)
{
RT_OBJECT_HOOK_CALL(rt_interrupt_switch_hook, ());
}
#endif
const unsigned int VECTOR_BASE = 0x00;
extern void rt_cpu_vector_set_base(unsigned int addr);
extern int system_vectors;
void rt_hw_vector_init(void)
{
rt_cpu_vector_set_base((unsigned int)&system_vectors);
}
#ifdef RT_USING_GIC_V2
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init(void)
{
rt_uint32_t gic_cpu_base;
rt_uint32_t gic_dist_base;
rt_uint32_t gic_irq_start;
/* initialize vector table */
rt_hw_vector_init();
/* initialize exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
#ifdef RT_USING_SMART
gic_dist_base = (uint32_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x2000);
gic_cpu_base = (uint32_t)rt_ioremap((void*)platform_get_gic_cpu_base(), 0x1000);
#else
gic_dist_base = platform_get_gic_dist_base();
gic_cpu_base = platform_get_gic_cpu_base();
#endif
gic_irq_start = GIC_IRQ_START;
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
arm_gic_cpu_init(0, gic_cpu_base);
}
#else
/**
* This function will initialize hardware interrupt
* Called by the primary cpu(cpu0)
*/
void rt_hw_interrupt_init(void)
{
rt_uint32_t gic_dist_base;
rt_uint32_t gic_irq_start;
/* initialize vector table */
rt_hw_vector_init();
/* initialize exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
#ifdef RT_USING_SMART
gic_dist_base = (uint32_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x10000);
#else
gic_dist_base = platform_get_gic_dist_base();
#endif
gic_irq_start = GIC_IRQ_START;
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
arm_gic_cpu_init(0);
arm_gic_redist_init(0);
}
#endif
/**
* This function will mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_mask(int vector)
{
arm_gic_mask(0, vector);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
arm_gic_umask(0, vector);
}
/**
* This function returns the active interrupt number.
* @param none
*/
int rt_hw_interrupt_get_irq(void)
{
return arm_gic_get_active_irq(0);
}
/**
* This function acknowledges the interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_ack(int vector)
{
arm_gic_ack(0, vector);
}
/**
* This function set interrupt CPU targets.
* @param vector: the interrupt number
* cpu_mask: target cpus mask, one bit for one core
*/
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
{
arm_gic_set_cpu(0, vector, cpu_mask);
}
/**
* This function get interrupt CPU targets.
* @param vector: the interrupt number
* @return target cpus mask, one bit for one core
*/
unsigned int rt_hw_interrupt_get_target_cpus(int vector)
{
return arm_gic_get_target_cpu(0, vector);
}
/**
* This function set interrupt triger mode.
* @param vector: the interrupt number
* mode: interrupt triger mode; 0: level triger, 1: edge triger
*/
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
{
arm_gic_set_configuration(0, vector, mode & IRQ_MODE_MASK);
}
/**
* This function get interrupt triger mode.
* @param vector: the interrupt number
* @return interrupt triger mode; 0: level triger, 1: edge triger
*/
unsigned int rt_hw_interrupt_get_triger_mode(int vector)
{
return arm_gic_get_configuration(0, vector);
}
/**
* This function set interrupt pending flag.
* @param vector: the interrupt number
*/
void rt_hw_interrupt_set_pending(int vector)
{
arm_gic_set_pending_irq(0, vector);
}
/**
* This function get interrupt pending flag.
* @param vector: the interrupt number
* @return interrupt pending flag, 0: not pending; 1: pending
*/
unsigned int rt_hw_interrupt_get_pending(int vector)
{
return arm_gic_get_pending_irq(0, vector);
}
/**
* This function clear interrupt pending flag.
* @param vector: the interrupt number
*/
void rt_hw_interrupt_clear_pending(int vector)
{
arm_gic_clear_pending_irq(0, vector);
}
/**
* This function set interrupt priority value.
* @param vector: the interrupt number
* priority: the priority of interrupt to set
*/
void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
{
arm_gic_set_priority(0, vector, priority);
}
/**
* This function get interrupt priority.
* @param vector: the interrupt number
* @return interrupt priority value
*/
unsigned int rt_hw_interrupt_get_priority(int vector)
{
return arm_gic_get_priority(0, vector);
}
/**
* This function set priority masking threshold.
* @param priority: priority masking threshold
*/
void rt_hw_interrupt_set_priority_mask(unsigned int priority)
{
arm_gic_set_interface_prior_mask(0, priority);
}
/**
* This function get priority masking threshold.
* @param none
* @return priority masking threshold
*/
unsigned int rt_hw_interrupt_get_priority_mask(void)
{
return arm_gic_get_interface_prior_mask(0);
}
/**
* This function set priority grouping field split point.
* @param bits: priority grouping field split point
* @return 0: success; -1: failed
*/
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
{
int status;
if (bits < 8)
{
arm_gic_set_binary_point(0, (7 - bits));
status = 0;
}
else
{
status = -1;
}
return (status);
}
/**
* This function get priority grouping field split point.
* @param none
* @return priority grouping field split point
*/
unsigned int rt_hw_interrupt_get_prior_group_bits(void)
{
unsigned int bp;
bp = arm_gic_get_binary_point(0) & 0x07;
return (7 - bp);
}
/**
* This function will install a interrupt service routine to a interrupt.
* @param vector the interrupt number
* @param new_handler the interrupt service routine to be installed
* @param old_handler the old interrupt service routine
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name)
{
rt_isr_handler_t old_handler = RT_NULL;
if (vector < MAX_HANDLERS)
{
old_handler = isr_table[vector].handler;
if (handler != RT_NULL)
{
#ifdef RT_USING_INTERRUPT_INFO
rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
#endif /* RT_USING_INTERRUPT_INFO */
isr_table[vector].handler = handler;
isr_table[vector].param = param;
}
}
return old_handler;
}
#ifdef RT_USING_SMP
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
{
#ifdef RT_USING_GIC_V2
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
#else
arm_gic_send_affinity_sgi(0, ipi_vector, cpu_mask, ROUTED_TO_SPEC);
#endif
}
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
{
/* note: ipi_vector maybe different with irq_vector */
rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
}
#endif
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard first version
*/
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include <rthw.h>
#include <board.h>
#define INT_IRQ 0x00
#define INT_FIQ 0x01
#define IRQ_MODE_TRIG_LEVEL (0x00) /* Trigger: level triggered interrupt */
#define IRQ_MODE_TRIG_EDGE (0x01) /* Trigger: edge triggered interrupt */
#define IRQ_MODE_MASK (0x01)
void rt_hw_vector_init(void);
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_mask(int vector);
void rt_hw_interrupt_umask(int vector);
int rt_hw_interrupt_get_irq(void);
void rt_hw_interrupt_ack(int vector);
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask);
unsigned int rt_hw_interrupt_get_target_cpus(int vector);
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode);
unsigned int rt_hw_interrupt_get_triger_mode(int vector);
void rt_hw_interrupt_set_pending(int vector);
unsigned int rt_hw_interrupt_get_pending(int vector);
void rt_hw_interrupt_clear_pending(int vector);
void rt_hw_interrupt_set_priority(int vector, unsigned int priority);
unsigned int rt_hw_interrupt_get_priority(int vector);
void rt_hw_interrupt_set_priority_mask(unsigned int priority);
unsigned int rt_hw_interrupt_get_priority_mask(void);
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits);
unsigned int rt_hw_interrupt_get_prior_group_bits(void);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name);
#ifdef RT_USING_SMP
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask);
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
#endif
#endif
+503
View File
@@ -0,0 +1,503 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-10 bernard porting to AM1808
* 2023-10-10 Shell Add permission control API
*/
#include <rthw.h>
#include <rtthread.h>
#define DBG_TAG "hw.mmu"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <board.h>
#include "cp15.h"
#include "mm_page.h"
#include "mmu.h"
#include <mm_aspace.h>
#include <tlb.h>
#ifdef RT_USING_SMART
#include <lwp_mm.h>
#include <lwp_arch.h>
#include "ioremap.h"
#else
#define KERNEL_VADDR_START 0
#endif
/* level1 page table, each entry for 1MB memory. */
volatile unsigned long MMUTable[4 * 1024] __attribute__((aligned(16 * 1024)));
unsigned long rt_hw_set_domain_register(unsigned long domain_val)
{
unsigned long old_domain;
asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");
return old_domain;
}
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd,
rt_uint32_t paddrStart, rt_uint32_t attr)
{
volatile rt_uint32_t *pTT;
volatile int i, nSec;
pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20);
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
for(i = 0; i <= nSec; i++)
{
*pTT = attr | (((paddrStart >> 20) + i) << 20);
pTT++;
}
}
void init_mm_setup(unsigned int *mtbl, unsigned int size, unsigned int pv_off)
{
unsigned int va;
for (va = 0; va < 0x1000; va++)
{
unsigned int vaddr = (va << 20);
if (vaddr >= KERNEL_VADDR_START && vaddr - KERNEL_VADDR_START < size)
{
mtbl[va] = ((va << 20) + pv_off) | NORMAL_MEM;
}
else if (vaddr >= (KERNEL_VADDR_START + pv_off) && vaddr - (KERNEL_VADDR_START + pv_off) < size)
{
mtbl[va] = (va << 20) | NORMAL_MEM;
}
else
{
mtbl[va] = 0;
}
}
}
#ifndef RT_USING_SMART
static void _init_map_section(rt_uint32_t *mmu_table, rt_uint32_t va,
rt_uint32_t size,rt_uint32_t pa, rt_uint32_t attr)
{
volatile rt_uint32_t *ptt;
volatile int i, num_section;
ptt = (rt_uint32_t *)mmu_table + (va >> ARCH_SECTION_SHIFT);
num_section = size >> ARCH_SECTION_SHIFT;
for(i = 0; i <= num_section; i++)
{
*ptt = attr | (((pa >> ARCH_SECTION_SHIFT) + i) << ARCH_SECTION_SHIFT);
ptt++;
}
}
#endif
void rt_hw_mem_setup_early(rt_uint32_t *early_mmu_talbe,
rt_uint32_t pv_off)
{
rt_uint32_t size = 0;
size = 0x100000 + (rt_uint32_t)&__bss_end;
size &= ~(0x100000 - 1);
#ifdef RT_USING_SMART
size -= KERNEL_VADDR_START;
init_mm_setup(early_mmu_talbe, size, pv_off);
#else
rt_uint32_t normal_attr = NORMAL_MEM;
extern unsigned char _reset;
rt_uint32_t va = (rt_uint32_t) &_reset;
/* The starting virtual address is aligned along 0x1000000. */
va &= (0x1000000 - 1);
size -= va;
_init_map_section(early_mmu_talbe, va, size, va + pv_off, normal_attr);
#endif
}
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
{
void *vaddr;
size_t length;
/* init kernel space */
#ifdef RT_USING_SMART
rt_aspace_init(&rt_kernel_space, (void *)USER_VADDR_TOP, -USER_VADDR_TOP, (void *)MMUTable);
#else
rt_aspace_init(&rt_kernel_space, (void *)0x1000, 0 - 0x1000, (void *)MMUTable);
#endif /* RT_USING_SMART */
/* set page table */
for(; size > 0; size--)
{
if (mdesc->paddr_start == (rt_uint32_t)ARCH_MAP_FAILED)
mdesc->paddr_start = mdesc->vaddr_start + PV_OFFSET;
vaddr = (void *)mdesc->vaddr_start;
length = mdesc->vaddr_end - mdesc->vaddr_start;
rt_aspace_map_static(&rt_kernel_space, &mdesc->varea, &vaddr, length,
mdesc->attr, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0);
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void*)MMUTable, sizeof MMUTable);
}
void rt_hw_mmu_init(void)
{
rt_cpu_dcache_clean_flush();
rt_cpu_icache_flush();
rt_hw_cpu_dcache_disable();
rt_hw_cpu_icache_disable();
rt_cpu_mmu_disable();
/*rt_hw_cpu_dump_page_table(MMUTable);*/
rt_hw_set_domain_register(0x55555555);
rt_cpu_tlb_set(MMUTable);
rt_cpu_mmu_enable();
rt_hw_cpu_icache_enable();
rt_hw_cpu_dcache_enable();
}
int rt_hw_mmu_map_init(struct rt_aspace *aspace, void* v_address, size_t size, size_t *vtable, size_t pv_off)
{
size_t l1_off, va_s, va_e;
if (!aspace || !vtable)
{
return -1;
}
va_s = (size_t)v_address;
va_e = (size_t)v_address + size - 1;
if ( va_e < va_s)
{
return -1;
}
va_s >>= ARCH_SECTION_SHIFT;
va_e >>= ARCH_SECTION_SHIFT;
if (va_s == 0)
{
return -1;
}
for (l1_off = va_s; l1_off <= va_e; l1_off++)
{
size_t v = vtable[l1_off];
if (v & ARCH_MMU_USED_MASK)
{
return -1;
}
}
#ifdef RT_USING_SMART
rt_ioremap_start = v_address;
rt_ioremap_size = size;
rt_mpr_start = rt_ioremap_start - rt_mpr_size;
#else
rt_mpr_start = (void *)((rt_size_t)0 - rt_mpr_size);
#endif
return 0;
}
int rt_hw_mmu_ioremap_init(rt_aspace_t aspace, void* v_address, size_t size)
{
#ifdef RT_IOREMAP_LATE
size_t loop_va;
size_t l1_off;
size_t *mmu_l1, *mmu_l2;
size_t sections;
/* for kernel ioremap */
if ((size_t)v_address < KERNEL_VADDR_START)
{
return -1;
}
/* must align to section */
if ((size_t)v_address & ARCH_SECTION_MASK)
{
return -1;
}
/* must align to section */
if (size & ARCH_SECTION_MASK)
{
return -1;
}
loop_va = (size_t)v_address;
sections = (size >> ARCH_SECTION_SHIFT);
while (sections--)
{
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
mmu_l1 = (size_t*)aspace->page_table + l1_off;
RT_ASSERT((*mmu_l1 & ARCH_MMU_USED_MASK) == 0);
mmu_l2 = (size_t*)rt_pages_alloc(0);
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + PV_OFFSET) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
else
{
/* error */
return -1;
}
loop_va += ARCH_SECTION_SIZE;
}
#endif
return 0;
}
static void _kenrel_unmap_4K(unsigned long *lv0_tbl, void *v_addr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t *)lv0_tbl + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
}
else
{
return;
}
if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
{
*(mmu_l2 + l2_off) = 0;
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
if (rt_pages_free(mmu_l2, 0))
{
*mmu_l1 = 0;
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
}
loop_va += ARCH_PAGE_SIZE;
}
static int _kenrel_map_4K(unsigned long *lv0_tbl, void *v_addr, void *p_addr,
size_t attr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t loop_pa = (size_t)p_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t *)lv0_tbl + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
rt_page_ref_inc(mmu_l2, 0);
}
else
{
mmu_l2 = (size_t *)rt_pages_alloc(0);
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + PV_OFFSET) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
else
{
/* error, quit */
return -1;
}
}
*(mmu_l2 + l2_off) = (loop_pa | attr);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
loop_va += ARCH_PAGE_SIZE;
loop_pa += ARCH_PAGE_SIZE;
return 0;
}
void *rt_hw_mmu_map(rt_aspace_t aspace, void *v_addr, void *p_addr, size_t size,
size_t attr)
{
int ret = -1;
void *unmap_va = v_addr;
size_t npages = size >> ARCH_PAGE_SHIFT;
// TODO trying with HUGEPAGE here
while (npages--)
{
ret = _kenrel_map_4K(aspace->page_table, v_addr, p_addr, attr);
if (ret != 0)
{
/* error, undo map */
while (unmap_va != v_addr)
{
rt_enter_critical();
_kenrel_unmap_4K(aspace->page_table, (void *)unmap_va);
rt_exit_critical();
unmap_va += ARCH_PAGE_SIZE;
}
break;
}
v_addr += ARCH_PAGE_SIZE;
p_addr += ARCH_PAGE_SIZE;
}
if (ret == 0)
{
return v_addr;
}
return NULL;
}
void rt_hw_mmu_unmap(rt_aspace_t aspace, void *v_addr, size_t size)
{
// caller guarantee that v_addr & size are page aligned
size_t npages = size >> ARCH_PAGE_SHIFT;
if (!aspace->page_table)
{
return;
}
while (npages--)
{
rt_enter_critical();
_kenrel_unmap_4K(aspace->page_table, v_addr);
rt_exit_critical();
v_addr += ARCH_PAGE_SIZE;
}
}
void rt_hw_aspace_switch(rt_aspace_t aspace)
{
if (aspace != &rt_kernel_space)
{
void *pgtbl = aspace->page_table;
pgtbl = rt_kmem_v2p(pgtbl);
rt_hw_mmu_switch(pgtbl);
rt_hw_tlb_invalidate_all_local();
}
}
void *rt_hw_mmu_v2p(rt_aspace_t aspace, void* v_addr)
{
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t tmp;
size_t pa;
l1_off = (size_t)v_addr >> ARCH_SECTION_SHIFT;
RT_ASSERT(aspace);
mmu_l1 = (size_t*)aspace->page_table + l1_off;
tmp = *mmu_l1;
switch (tmp & ARCH_MMU_USED_MASK)
{
case 0: /* not used */
break;
case 1: /* page table */
mmu_l2 = (size_t *)((tmp & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
l2_off = (((size_t)v_addr & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
pa = *(mmu_l2 + l2_off);
if (pa & ARCH_MMU_USED_MASK)
{
if ((pa & ARCH_MMU_USED_MASK) == 1)
{
/* large page, not support */
break;
}
pa &= ~(ARCH_PAGE_MASK);
pa += ((size_t)v_addr & ARCH_PAGE_MASK);
return (void*)pa;
}
break;
case 2:
case 3:
/* section */
if (tmp & ARCH_TYPE_SUPERSECTION)
{
/* super section, not support */
break;
}
pa = (tmp & ~ARCH_SECTION_MASK);
pa += ((size_t)v_addr & ARCH_SECTION_MASK);
return (void*)pa;
}
return ARCH_MAP_FAILED;
}
int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size,
enum rt_mmu_cntl cmd)
{
return -RT_ENOSYS;
}
#define KPTE_START (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT)
void *rt_hw_mmu_pgtbl_create(void)
{
size_t *mmu_table;
mmu_table = (size_t *)rt_pages_alloc_ext(2, PAGE_ANY_AVAILABLE);
if (!mmu_table)
{
return RT_NULL;
}
rt_memcpy(mmu_table + KPTE_START, (size_t *)rt_kernel_space.page_table + KPTE_START, ARCH_PAGE_SIZE);
rt_memset(mmu_table, 0, 3 * ARCH_PAGE_SIZE);
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * ARCH_PAGE_SIZE);
return mmu_table;
}
void rt_hw_mmu_pgtbl_delete(void *pgtbl)
{
rt_pages_free(pgtbl, 2);
}
+215
View File
@@ -0,0 +1,215 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-25 quanzhao the first version
* 2023-10-10 Shell Add permission control API
*/
#ifndef __MMU_H_
#define __MMU_H_
#include <rtthread.h>
#include <mm_aspace.h>
#define DESC_SEC (0x2)
#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */
#define MEMWB (3<<2) /* write back, no write allocate */
#define MEMWT (2<<2) /* write through, no write allocate */
#define SHAREDEVICE (1<<2) /* shared device */
#define STRONGORDER (0<<2) /* strong ordered */
#define XN (1<<4) /* eXecute Never */
#ifdef RT_USING_SMART
#define AP_RW (1<<10) /* supervisor=RW, user=No */
#define AP_RO ((1<<10) |(1 << 15)) /* supervisor=RW, user=No */
#else
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
#define AP_RO (2<<10) /* supervisor=RW, user=RO */
#endif
#define SHARED (1<<16) /* shareable */
#define DOMAIN_FAULT (0x0)
#define DOMAIN_CHK (0x1)
#define DOMAIN_NOTCHK (0x3)
#define DOMAIN0 (0x0<<5)
#define DOMAIN1 (0x1<<5)
#define DOMAIN0_ATTR (DOMAIN_CHK<<0)
#define DOMAIN1_ATTR (DOMAIN_FAULT<<2)
/* device mapping type */
#define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN)
/* normal memory mapping type */
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
#define STRONG_ORDER_MEM (SHARED|AP_RO|XN|DESC_SEC)
struct mem_desc
{
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t attr;
struct rt_varea varea;
};
#define MMU_MAP_MTBL_XN (1<<0)
#define MMU_MAP_MTBL_A (1<<1)
#define MMU_MAP_MTBL_B (1<<2)
#define MMU_MAP_MTBL_C (1<<3)
#define MMU_MAP_MTBL_AP01(x) (x<<4)
#define MMU_MAP_MTBL_TEX(x) (x<<6)
#define MMU_MAP_MTBL_AP2(x) (x<<9)
#define MMU_MAP_MTBL_SHARE (1<<10)
#define MMU_MAP_MTBL_NG(x) (x<<11)
#define MMU_MAP_K_ROCB ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RO ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RWCB ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RW ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_DEVICE ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_ROCB ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RO ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RWCB ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RW ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_DEVICE ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_TRACE(attr) (attr)
#define ARCH_SECTION_SHIFT 20
#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
#define ARCH_SECTION_MASK (ARCH_SECTION_SIZE - 1)
#define ARCH_PAGE_SHIFT 12
#define ARCH_PAGE_SIZE (1 << ARCH_PAGE_SHIFT)
#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
#define ARCH_PAGE_TBL_SHIFT 10
#define ARCH_PAGE_TBL_SIZE (1 << ARCH_PAGE_TBL_SHIFT)
#define ARCH_PAGE_TBL_MASK (ARCH_PAGE_TBL_SIZE - 1)
#define ARCH_MMU_USED_MASK 3
#define ARCH_TYPE_SUPERSECTION (1 << 18)
#define ARCH_ADDRESS_WIDTH_BITS 32
#define ARCH_VADDR_WIDTH 32
/**
* *info it's possible to map (-1ul & ~ARCH_PAGE_MASK) but a not aligned -1 is
* never returned on a successful mapping
*/
#define ARCH_MAP_FAILED ((void *)-1)
#define RT_HW_MMU_PROT_READ 1
#define RT_HW_MMU_PROT_WRITE 2
#define RT_HW_MMU_PROT_EXECUTE 4
#define RT_HW_MMU_PROT_KERNEL 8
#define RT_HW_MMU_PROT_USER 16
#define RT_HW_MMU_PROT_CACHE 32
int rt_hw_mmu_ioremap_init(struct rt_aspace *aspace, void *v_address, size_t size);
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size);
void rt_hw_mmu_setup(struct rt_aspace *aspace, struct mem_desc *mdesc, int desc_nr);
void rt_hw_mmu_init(void);
int rt_hw_mmu_map_init(struct rt_aspace *aspace, void *v_address, size_t size, size_t *vtable, size_t pv_off);
void *rt_hw_mmu_map(struct rt_aspace *aspace, void *v_addr, void *p_addr, size_t size, size_t attr);
void rt_hw_mmu_unmap(struct rt_aspace *aspace, void *v_addr, size_t size);
void rt_hw_aspace_switch(struct rt_aspace *aspace);
void rt_hw_mmu_switch(void *tbl);
void *rt_hw_mmu_v2p(struct rt_aspace *aspace, void *vaddr);
void rt_hw_mmu_kernel_map_init(struct rt_aspace *aspace, size_t vaddr_start, size_t size);
void *rt_hw_mmu_tbl_get(void);
int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd);
void *rt_hw_mmu_pgtbl_create(void);
void rt_hw_mmu_pgtbl_delete(void *pgtbl);
#define AP_APX_MASK (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x3))
#define AP_APX_URW_KRW (MMU_MAP_MTBL_AP2(0x0) | MMU_MAP_MTBL_AP01(0x3))
#define AP_APX_URO_KRO (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x2))
/**
* @brief Remove permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be removed
* @return size_t returned attribution
*/
rt_inline size_t rt_hw_mmu_attr_rm_perm(size_t attr, rt_base_t prot)
{
switch (prot)
{
/* remove write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
if ((attr & AP_APX_MASK) == AP_APX_URW_KRW)
attr &= ~MMU_MAP_MTBL_AP01(0x1);
break;
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
switch (attr & AP_APX_MASK)
{
case MMU_MAP_MTBL_AP01(0):
break;
case MMU_MAP_MTBL_AP01(3):
attr = (attr & AP_APX_MASK) | AP_APX_URO_KRO;
default:
attr |= MMU_MAP_MTBL_AP2(0x1);
break;
}
break;
default:
RT_ASSERT(0);
}
return attr;
}
/**
* @brief Add permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be added
* @return size_t returned attribution
*/
rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot)
{
switch (prot)
{
/* add write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
attr |= MMU_MAP_MTBL_AP01(0x3);
attr &= ~MMU_MAP_MTBL_AP2(0x1);
break;
default:
RT_ASSERT(0);
}
return attr;
}
/**
* @brief Test permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be test
* @return rt_bool_t RT_TRUE if the prot is allowed, otherwise RT_FALSE
*/
rt_inline rt_bool_t rt_hw_mmu_attr_test_perm(size_t attr, rt_base_t prot)
{
rt_bool_t rc = 0;
switch (prot)
{
/* test write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
rc = (AP_APX_MASK & attr) == (AP_APX_URW_KRW);
break;
default:
RT_ASSERT(0);
}
return rc;
}
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include "pmu.h"
#define DBG_TAG "PMU"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
void rt_hw_pmu_dump_feature(void)
{
unsigned long reg;
reg = rt_hw_pmu_get_control();
LOG_D("ARM PMU Implementor: %c, ID code: %02x, %d counters\n",
reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f);
RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f));
RT_UNUSED(reg);
}
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __PMU_H__
#define __PMU_H__
#include "board.h"
/* Number of counters */
#define ARM_PMU_CNTER_NR 4
enum rt_hw_pmu_event_type {
ARM_PMU_EVENT_PMNC_SW_INCR = 0x00,
ARM_PMU_EVENT_L1_ICACHE_REFILL = 0x01,
ARM_PMU_EVENT_ITLB_REFILL = 0x02,
ARM_PMU_EVENT_L1_DCACHE_REFILL = 0x03,
ARM_PMU_EVENT_L1_DCACHE_ACCESS = 0x04,
ARM_PMU_EVENT_DTLB_REFILL = 0x05,
ARM_PMU_EVENT_MEM_READ = 0x06,
ARM_PMU_EVENT_MEM_WRITE = 0x07,
ARM_PMU_EVENT_INSTR_EXECUTED = 0x08,
ARM_PMU_EVENT_EXC_TAKEN = 0x09,
ARM_PMU_EVENT_EXC_EXECUTED = 0x0A,
ARM_PMU_EVENT_CID_WRITE = 0x0B,
};
/* Enable bit */
#define ARM_PMU_PMCR_E (0x01 << 0)
/* Event counter reset */
#define ARM_PMU_PMCR_P (0x01 << 1)
/* Cycle counter reset */
#define ARM_PMU_PMCR_C (0x01 << 2)
/* Cycle counter divider */
#define ARM_PMU_PMCR_D (0x01 << 3)
#ifdef __GNUC__
rt_inline void rt_hw_pmu_enable_cnt(int divide64)
{
unsigned long pmcr;
unsigned long pmcntenset;
asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr));
pmcr |= ARM_PMU_PMCR_E | ARM_PMU_PMCR_P | ARM_PMU_PMCR_C;
if (divide64)
pmcr |= ARM_PMU_PMCR_D;
else
pmcr &= ~ARM_PMU_PMCR_D;
asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr));
/* enable all the counters */
pmcntenset = ~0;
asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(pmcntenset));
/* clear overflows(just in case) */
asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r"(pmcntenset));
}
rt_inline unsigned long rt_hw_pmu_get_control(void)
{
unsigned long pmcr;
asm ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr));
return pmcr;
}
rt_inline unsigned long rt_hw_pmu_get_ceid(void)
{
unsigned long reg;
/* only PMCEID0 is supported, PMCEID1 is RAZ. */
asm ("mrc p15, 0, %0, c9, c12, 6" : "=r"(reg));
return reg;
}
rt_inline unsigned long rt_hw_pmu_get_cnten(void)
{
unsigned long pmcnt;
asm ("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcnt));
return pmcnt;
}
rt_inline void rt_hw_pmu_reset_cycle(void)
{
unsigned long pmcr;
asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr));
pmcr |= ARM_PMU_PMCR_C;
asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr));
asm volatile ("isb");
}
rt_inline void rt_hw_pmu_reset_event(void)
{
unsigned long pmcr;
asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr));
pmcr |= ARM_PMU_PMCR_P;
asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr));
asm volatile ("isb");
}
rt_inline unsigned long rt_hw_pmu_get_cycle(void)
{
unsigned long cyc;
asm volatile ("isb");
asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cyc));
return cyc;
}
rt_inline void rt_hw_pmu_select_counter(int idx)
{
RT_ASSERT(idx < ARM_PMU_CNTER_NR);
asm volatile ("mcr p15, 0, %0, c9, c12, 5" : : "r"(idx));
/* Linux add an isb here, don't know why here. */
asm volatile ("isb");
}
rt_inline void rt_hw_pmu_select_event(int idx,
enum rt_hw_pmu_event_type eve)
{
RT_ASSERT(idx < ARM_PMU_CNTER_NR);
rt_hw_pmu_select_counter(idx);
asm volatile ("mcr p15, 0, %0, c9, c13, 1" : : "r"(eve));
}
rt_inline unsigned long rt_hw_pmu_read_counter(int idx)
{
unsigned long reg;
rt_hw_pmu_select_counter(idx);
asm volatile ("isb");
asm volatile ("mrc p15, 0, %0, c9, c13, 2" : "=r"(reg));
return reg;
}
rt_inline unsigned long rt_hw_pmu_get_ovsr(void)
{
unsigned long reg;
asm volatile ("isb");
asm ("mrc p15, 0, %0, c9, c12, 3" : "=r"(reg));
return reg;
}
rt_inline void rt_hw_pmu_clear_ovsr(unsigned long reg)
{
asm ("mcr p15, 0, %0, c9, c12, 3" : : "r"(reg));
asm volatile ("isb");
}
#endif
void rt_hw_pmu_dump_feature(void);
#endif /* end of include guard: __PMU_H__ */
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-23 Bernard the first version
* 2011-10-05 Bernard add thumb mode
*/
#include <rtthread.h>
#include <cpuport.h>
#include <board.h>
/**
* @addtogroup ARM Cortex-A
*/
/*@{*/
/**
* 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)_thread_start; /* 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) = (rt_uint32_t)tentry; /* r1 : argument 2 for trampoline */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument 1 */
/* cpsr */
if ((rt_uint32_t)tentry & 0x01)
*(--stk) = SVCMODE | 0x20; /* thumb mode */
else
*(--stk) = SVCMODE; /* arm mode */
#ifdef RT_USING_SMART
*(--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;
}
/*@}*/
+695
View File
@@ -0,0 +1,695 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
* 2018-11-22 Jesven in the interrupt context, use rt_scheduler_do_irq_switch checks
* and switches to a new thread
* 2024-01-16 huanghe restructure this code section following the aarch64 architectural style
*/
#include "rtconfig.h"
#define ARM_CPU_STACK_SIZE_OFFSET 12
#define ARM_CPU_STACK_SIZE (1<<ARM_CPU_STACK_SIZE_OFFSET)
.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 */
/*Load the physical address of a symbol into a register.
Through pv_off calculates the offset of the physical address */
.macro get_phy, reg, symbol, _pvoff
ldr \reg, =\symbol
add \reg, \_pvoff
.endm
/*Calculate the offset between the physical address and the virtual address of the "_reset".*/
.macro get_pvoff, tmp, out
ldr \tmp, =_reset
adr \out, _reset
sub \out, \out, \tmp
.endm
pv_off .req r11 /* Used to store the offset between physical address and the virtual address */
cpu_id .req r10 /* Used to store the cpu id */
/* reset entry */
.globl _reset
_reset:
/* Calculate the offset between the physical address and the virtual address */
get_pvoff r0, pv_off
/* exit hyp mode */
bl init_cpu_mode
/* clear bss section */
bl init_kernel_bss
/* Initializes the assembly environment stack */
bl init_cpu_stack_early
/* init mmu */
b init_mmu_page_table_early
init_cpu_stack_early:
cps #Mode_SVC
get_phy r0, svc_stack_top, pv_off
mov sp, r0
#ifdef RT_USING_FPU
mov r4, #0xfffffff
mcr p15, 0, r4, c1, c0, 2
#endif
mov pc, lr
init_kernel_bss:
/* enable I cache + branch prediction */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1<<12)
orr r0, r0, #(1<<11)
mcr p15, 0, r0, c1, c0, 0
mov r0,#0 /* get a zero */
get_phy r1, __bss_start, pv_off
get_phy r2, __bss_end, pv_off
bss_loop:
cmp r1,r2 /* check if data to clear */
strlo r0,[r1],#4 /* clear 4 bytes */
blo bss_loop /* loop until done */
mov pc, lr
init_cpu_mode:
#ifdef ARCH_ARMV8
/* Check for HYP mode */
mrs r0, cpsr_all
and r0, r0, #0x1F
mov r8, #0x1A
cmp r0, r8
beq overHyped
b continue_exit
overHyped: /* Get out of HYP mode */
mov r9, lr
/* HYP mode has a dedicated register, called ELR_hyp,
to store the exception return address.
The lr register needs to be temporarily saved,
otherwise "mov pc lr" cannot be used after switching modes. */
adr r1, continue_exit
msr ELR_hyp, r1
mrs r1, cpsr_all
and r1, r1, #0xFFFFFFE0 /* CPSR_MODE_MASK */
orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
msr SPSR_hyp, r1
eret
continue_exit:
mov lr ,r9
#endif
#ifdef SOC_BCM283x
/* Suspend the other cpu cores */
mrc p15, 0, r0, c0, c0, 5
ands r0, #3
bne _halt
/* Disable IRQ & FIQ */
cpsid if
/* Check for HYP mode */
mrs r0, cpsr_all
and r0, r0, #0x1F
mov r8, #0x1A
cmp r0, r8
beq overHyped
b continue_exit
overHyped: /* Get out of HYP mode */
mov r9, lr
/* HYP mode has a dedicated register, called ELR_hyp,
to store the exception return address.
The lr register needs to be temporarily saved,
otherwise "mov pc lr" cannot be used after switching modes. */
adr r1, continue_exit
msr ELR_hyp, r1
mrs r1, cpsr_all
and r1, r1, #0xFFFFFFE0 /* CPSR_MODE_MASK */
orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
msr SPSR_hyp, r1
eret
continue_exit:
mov lr ,r9
/* set the cpu to SVC32 mode and disable interrupt */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x13
msr cpsr_c, r0
#endif
/* invalid tlb before enable mmu */
mrc p15, 0, r0, c1, c0, 0
bic r0, #1
mcr p15, 0, r0, c1, c0, 0
dsb
isb
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 /* iciallu */
mcr p15, 0, r0, c7, c5, 6 /* bpiall */
dsb
isb
mov pc, lr
init_mmu_page_table_early:
get_phy r0, init_mtbl, pv_off
mov r1, pv_off
bl rt_hw_mem_setup_early
/* get cpu id */
bl rt_hw_cpu_id_early
mov cpu_id ,r0
/* enable_mmu_page_table_early is changed to master_core_startup */
ldr lr, =master_core_startup
cmp cpu_id, #0
beq enable_mmu_page_table_early
#ifdef RT_USING_SMP
#ifdef RT_SMP_AUTO_BOOT
/* if cpu id > 0, stop or wait */
ldr r0, =secondary_cpu_entry
mov r1, #0
str r1, [r0] /* clean secondary_cpu_entry */
#endif
#endif
secondary_loop:
@ cpu core 1 goes into sleep until core 0 wakeup it
wfe
#ifdef RT_SMP_AUTO_BOOT
ldr r1, =secondary_cpu_entry
ldr r0, [r1]
cmp r0, #0
blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */
#endif /* RT_SMP_AUTO_BOOT */
b secondary_loop
enable_mmu_page_table_early:
/* init TTBR0 */
get_phy r0, init_mtbl, pv_off
mcr p15, #0, r0, c2, c0, #0
dmb
ldr r0,=#0x55555555
mcr p15, #0, r0, c3, c0, #0
/* disable ttbr1 */
mov r0, #(1 << 5) /* PD1=1 */
mcr p15, 0, r0, c2, c0, 2 /* ttbcr */
/* init stack for cpu mod */
cps #Mode_UND
ldr r1,=und_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_IRQ
ldr r1, =irq_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_FIQ
ldr r1, =irq_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_ABT
ldr r1, =abt_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_SVC
ldr r1, =svc_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
/* invalid tlb before enable mmu */
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 /* iciallu */
mcr p15, 0, r0, c7, c5, 6 /* bpiall */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x7 /* clear bit1~3 */
orr r0, #((1 << 12) | (1 << 11)) /* instruction cache, branch prediction */
orr r0, #((1 << 2) | (1 << 0)) /* data cache, mmu enable */
mcr p15, 0, r0, c1, c0, 0
dsb
isb
mov pc, lr
master_core_startup :
mov r0 ,pv_off
bl rt_kmem_pvoff_set
ldr lr, =rtthread_startup
mov pc, lr
.global rt_hw_mmu_tbl_get
rt_hw_mmu_tbl_get:
mrc p15, 0, r0, c2, c0, 0 /* ttbr0 */
bic r0, #0x18
mov pc, lr
.weak rt_hw_cpu_id_early
rt_hw_cpu_id_early:
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #0xf
mov pc, lr
#ifdef RT_USING_SMP
.global rt_secondary_cpu_entry
rt_secondary_cpu_entry:
ldr r0, =_reset
adr pv_off, _reset
sub pv_off, pv_off, r0
bl init_cpu_stack_early
/* init mmu */
bl rt_hw_cpu_id_early
mov cpu_id ,r0
ldr lr ,= rt_hw_secondary_cpu_bsp_start
b enable_mmu_page_table_early
#endif
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
.section .text.isr, "ax"
.align 5
.globl vector_fiq
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc, lr, #4
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
.globl rt_current_thread
.globl vmm_thread
.globl vmm_virq_check
.align 5
.globl vector_irq
vector_irq:
#ifdef RT_USING_SMP
stmfd sp!, {r0, r1}
cps #Mode_SVC
mov r0, sp /* svc_sp */
mov r1, lr /* svc_lr */
cps #Mode_IRQ
sub lr, #4
stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
stmfd r0!, {r2 - r12}
ldmfd sp!, {r1, r2} /* original r0, r1 */
stmfd r0!, {r1 - r2}
mrs r1, spsr /* original mode */
stmfd r0!, {r1}
#ifdef RT_USING_SMART
stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
sub r0, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb r0!, {d0-d15}
vstmdb r0!, {d16-d31}
vmrs r5, fpscr
stmfd r0!, {r5}
1:
stmfd r0!, {r6}
#endif
/* now irq stack is clean */
/* r0 is task svc_sp */
/* backup r0 -> r8 */
mov r8, r0
cps #Mode_SVC
mov sp, r8
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
mov r0, r8
bl rt_scheduler_do_irq_switch
b rt_hw_context_switch_exit
#else
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
/* if rt_thread_switch_interrupt_flag set, jump to
* rt_hw_context_switch_interrupt_do and don't return */
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
#ifdef RT_USING_SMART
ldmfd sp!, {r0-r12,lr}
cps #Mode_SVC
push {r0-r12}
mov r7, lr
cps #Mode_IRQ
mrs r4, spsr
sub r5, lr, #4
cps #Mode_SVC
and r6, r4, #0x1f
cmp r6, #0x10
bne 1f
msr spsr_csxf, r4
mov lr, r5
pop {r0-r12}
b arch_ret_to_user
1:
mov lr, r7
cps #Mode_IRQ
msr spsr_csxf, r4
mov lr, r5
cps #Mode_SVC
pop {r0-r12}
cps #Mode_IRQ
movs pc, lr
#else
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
#endif
rt_hw_context_switch_interrupt_do:
mov r1, #0 /* clear flag */
str r1, [r0]
mov r1, sp /* r1 point to {r0-r3} in stack */
add sp, sp, #4*4
ldmfd sp!, {r4-r12,lr} /* reload saved registers */
mrs r0, spsr /* get cpsr of interrupt thread */
sub r2, lr, #4 /* save old task's pc to r2 */
/* Switch to SVC mode with no interrupt. If the usr mode guest is
* interrupted, this will just switch to the stack of kernel space.
* save the registers in kernel space won't trigger data abort. */
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
stmfd sp!, {r2} /* push old task's pc */
stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */
ldmfd r1, {r1-r4} /* restore r0-r3 of the interrupt thread */
stmfd sp!, {r1-r4} /* push old task's r0-r3 */
stmfd sp!, {r0} /* push old task's cpsr */
#ifdef RT_USING_SMART
stmfd sp, {r13, r14}^ /*push usr_sp, usr_lr */
sub sp, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb sp!, {d0-d15}
vstmdb sp!, {d16-d31}
vmrs r5, fpscr
stmfd sp!, {r5}
1:
stmfd sp!, {r6}
#endif
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] /* store sp in preempted tasks's TCB */
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
ldr sp, [r6] /* get new task's stack pointer */
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#ifdef RT_USING_FPU
/* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq 1f
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d16-d31}
vldmia sp!, {d0-d15}
1:
#endif
#ifdef RT_USING_SMART
ldmfd sp, {r13, r14}^ /*pop usr_sp, usr_lr */
add sp, #8
#endif
ldmfd sp!, {r4} /* pop new task's cpsr to spsr */
msr spsr_cxsf, r4
#ifdef RT_USING_SMART
and r4, #0x1f
cmp r4, #0x10
bne 1f
ldmfd sp!, {r0-r12,lr}
ldmfd sp!, {lr}
b arch_ret_to_user
1:
#endif
/* pop new task's r0-r12,lr & pc, copy spsr to cpsr */
ldmfd sp!, {r0-r12,lr,pc}^
#endif
.macro push_svc_reg
sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
stmia sp, {r0 - r12} /* Calling r0-r12 */
mov r0, sp
add sp, sp, #17 * 4
mrs r6, spsr /* Save CPSR */
str lr, [r0, #15*4] /* Push PC */
str r6, [r0, #16*4] /* Push CPSR */
and r1, r6, #0x1f
cmp r1, #0x10
cps #Mode_SYS
streq sp, [r0, #13*4] /* Save calling SP */
streq lr, [r0, #14*4] /* Save calling PC */
cps #Mode_SVC
strne sp, [r0, #13*4] /* Save calling SP */
strne lr, [r0, #14*4] /* Save calling PC */
.endm
.align 5
.weak vector_swi
vector_swi:
push_svc_reg
bl rt_hw_trap_swi
b .
.align 5
.globl vector_undef
vector_undef:
push_svc_reg
bl rt_hw_trap_undef
#ifdef RT_USING_FPU
cps #Mode_UND
sub sp, sp, #17 * 4
ldr lr, [sp, #15*4]
ldmia sp, {r0 - r12}
add sp, sp, #17 * 4
movs pc, lr
#endif
b .
.align 5
.globl vector_pabt
vector_pabt:
push_svc_reg
#ifdef RT_USING_SMART
/* cp Mode_ABT stack to SVC */
sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
mov lr, r0
ldmia lr, {r0 - r12}
stmia sp, {r0 - r12}
add r1, lr, #13 * 4
add r2, sp, #13 * 4
ldmia r1, {r4 - r7}
stmia r2, {r4 - r7}
mov r0, sp
bl rt_hw_trap_pabt
/* return to user */
ldr lr, [sp, #16*4] /* orign spsr */
msr spsr_cxsf, lr
ldr lr, [sp, #15*4] /* orign pc */
ldmia sp, {r0 - r12}
add sp, #17 * 4
b arch_ret_to_user
#else
bl rt_hw_trap_pabt
b .
#endif
.align 5
.globl vector_dabt
vector_dabt:
push_svc_reg
#ifdef RT_USING_SMART
/* cp Mode_ABT stack to SVC */
sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
mov lr, r0
ldmia lr, {r0 - r12}
stmia sp, {r0 - r12}
add r1, lr, #13 * 4
add r2, sp, #13 * 4
ldmia r1, {r4 - r7}
stmia r2, {r4 - r7}
mov r0, sp
bl rt_hw_trap_dabt
/* return to user */
ldr lr, [sp, #16*4] /* orign spsr */
msr spsr_cxsf, lr
ldr lr, [sp, #15*4] /* orign pc */
ldmia sp, {r0 - r12}
add sp, #17 * 4
b arch_ret_to_user
#else
bl rt_hw_trap_dabt
b .
#endif
.align 5
.globl vector_resv
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .
.global rt_hw_clz
rt_hw_clz:
clz r0, r0
bx lr
#include "asm-generic.h"
START_POINT(_thread_start)
mov r10, lr
blx r1
blx r10
b . /* never here */
START_POINT_END(_thread_start)
.data
.align 14
init_mtbl:
.space (4*4096) /* The L1 translation table therefore contains 4096 32-bit (word-sized) entries. */
.global rt_hw_mmu_switch
rt_hw_mmu_switch:
orr r0, #0x18
mcr p15, 0, r0, c2, c0, 0 // ttbr0
//invalid tlb
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 //iciallu
mcr p15, 0, r0, c7, c5, 6 //bpiall
dsb
isb
mov pc, lr
.global rt_hw_set_process_id
rt_hw_set_process_id:
LSL r0, r0, #8
MCR p15, 0, r0, c13, c0, 1
mov pc, lr
.bss
.align 3 /* align to 2~3=8 */
.cpus_stack:
svc_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
svc_stack_top:
irq_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
irq_stack_top:
und_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
und_stack_top:
abt_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
abt_stack_top:
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-12 WangXiaoyao the first version
*/
#ifndef __TLB_H__
#define __TLB_H__
#include "mm_aspace.h"
#include <rtthread.h>
#include <stddef.h>
#include <stdint.h>
#define dsb(scope) __asm__ volatile("dsb " #scope : : : "memory")
#define isb() __asm__ volatile("isb" : : : "memory")
#define STORE_CP32(r, name...) "mcr " RT_STRINGIFY(CP32(%r, name)) ";"
#define WRITE_CP32(v, name...) do { \
register uint32_t _r = (v); \
asm volatile(STORE_CP32(0, name) : : "r" (_r)); \
} while (0)
static inline void rt_hw_tlb_invalidate_all(void)
{
asm volatile ("mcr p15, 0, r0, c8, c7, 0\ndsb\nisb" ::: "memory");
}
static inline void rt_hw_tlb_invalidate_all_local(void)
{
rt_hw_tlb_invalidate_all();
}
static inline void rt_hw_tlb_invalidate_aspace(rt_aspace_t aspace)
{
rt_hw_tlb_invalidate_all();
}
static inline void rt_hw_tlb_invalidate_range(rt_aspace_t aspace, void *start,
size_t size, size_t stride)
{
rt_hw_tlb_invalidate_all();
}
#endif /* __TLB_H__ */
+390
View File
@@ -0,0 +1,390 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <board.h>
#include <backtrace.h>
#include "interrupt.h"
#include "mm_fault.h"
#include <rtdbg.h>
#ifdef RT_USING_FINSH
extern long list_thread(void);
#endif
#ifdef RT_USING_SMART
#include <lwp.h>
#include <lwp_arch.h>
#ifdef LWP_USING_CORE_DUMP
#include <lwp_core_dump.h>
#endif
void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info)
{
uint32_t mode = regs->cpsr;
if ((mode & 0x1f) == 0x10)
{
rt_kprintf("%s! pc = 0x%08x\n", info, regs->pc - pc_adj);
#ifdef LWP_USING_CORE_DUMP
lwp_core_dump(regs, pc_adj);
#endif
sys_exit_group(-1);
}
}
int check_data_abort(struct rt_hw_exp_stack *regs)
{
struct rt_lwp *lwp;
void *dfar = RT_NULL;
rt_base_t dfsr = RT_NULL;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfar));
__asm__ volatile("mrc p15, 0, %0, c5, c0, 0" : "=r"(dfsr));
struct rt_aspace_fault_msg msg = {
.fault_op = MM_FAULT_OP_WRITE,
.fault_type = MM_FAULT_TYPE_PAGE_FAULT,
.fault_vaddr = dfar,
};
lwp = lwp_self();
if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg))
{
regs->pc -= 8;
return 1;
}
return 0;
}
int check_prefetch_abort(struct rt_hw_exp_stack *regs)
{
struct rt_lwp *lwp;
void *ifar = RT_NULL;
rt_base_t ifsr = RT_NULL;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifar));
__asm__ volatile("mrc p15, 0, %0, c5, c0, 1" : "=r"(ifsr));
struct rt_aspace_fault_msg msg = {
.fault_op = MM_FAULT_OP_READ,
.fault_type = MM_FAULT_TYPE_PAGE_FAULT,
.fault_vaddr = ifar,
};
lwp = lwp_self();
if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg))
{
regs->pc -= 4;
return 1;
}
return 0;
}
#endif
/**
* 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);
#ifdef RT_USING_SMART
{
uint32_t v;
asm volatile ("MRC p15, 0, %0, c5, c0, 0":"=r"(v));
rt_kprintf("dfsr:0x%08x\n", v);
asm volatile ("MRC p15, 0, %0, c2, c0, 0":"=r"(v));
rt_kprintf("ttbr0:0x%08x\n", v);
asm volatile ("MRC p15, 0, %0, c6, c0, 0":"=r"(v));
rt_kprintf("dfar:0x%08x\n", v);
rt_kprintf("0x%08x -> 0x%08x\n", v, rt_kmem_v2p((void *)v));
}
#endif
}
/**
* 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
*/
#ifdef RT_USING_FPU
void set_fpexc(rt_uint32_t val);
#endif
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
{
#ifdef RT_USING_FPU
{
uint32_t ins;
uint32_t addr;
if (regs->cpsr & (1 << 5))
{
/* thumb mode */
addr = regs->pc - 2;
ins = (uint32_t)*(uint16_t *)addr;
if ((ins & (3 << 11)) != 0)
{
/* 32 bit ins */
ins <<= 16;
ins += *(uint16_t *)(addr + 2);
}
}
else
{
addr = regs->pc - 4;
ins = *(uint32_t *)addr;
}
if ((ins & 0xe00) == 0xa00)
{
/* float ins */
set_fpexc(1U << 30);
regs->pc = addr;
return;
}
}
#endif
#ifdef RT_USING_SMART
check_user_fault(regs, 4, "User undefined instruction");
#endif
rt_unwind(regs, 4);
rt_kprintf("undefined instruction:\n");
rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* The software interrupt instruction (SWI) is used for entering
* Supervisor mode, usually to request a particular supervisor
* function.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_swi(struct rt_hw_exp_stack *regs)
{
rt_kprintf("software interrupt:\n");
rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during an instruction prefetch.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs)
{
#ifdef RT_USING_SMART
if (dbg_check_event(regs, 4))
{
return;
}
if (check_prefetch_abort(regs))
{
return;
}
check_user_fault(regs, 4, "User prefetch abort");
#endif
rt_unwind(regs, 4);
rt_kprintf("prefetch abort:\n");
rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* An abort indicates that the current memory access cannot be completed,
* which occurs during a data access.
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs)
{
#ifdef RT_USING_SMART
if (dbg_check_event(regs, 8))
{
return;
}
if (check_data_abort(regs))
{
return;
}
check_user_fault(regs, 8, "User data abort");
#endif
rt_unwind(regs, 8);
rt_kprintf("data abort:");
rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
/**
* Normally, system will never reach here
*
* @param regs system registers
*
* @note never invoke this function in application
*/
void rt_hw_trap_resv(struct rt_hw_exp_stack *regs)
{
rt_kprintf("reserved trap:\n");
rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
list_thread();
#endif
rt_hw_cpu_shutdown();
}
void rt_hw_trap_irq(void)
{
#ifdef SOC_BCM283x
extern rt_uint8_t core_timer_flag;
void *param;
uint32_t irq;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
uint32_t value = 0;
value = IRQ_PEND_BASIC & 0x3ff;
if(core_timer_flag != 0)
{
uint32_t cpu_id = rt_hw_cpu_id();
uint32_t int_source = CORE_IRQSOURCE(cpu_id);
if (int_source & 0x0f)
{
if (int_source & 0x08)
{
isr_func = isr_table[IRQ_ARM_TIMER].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[IRQ_ARM_TIMER].counter++;
#endif
if (isr_func)
{
param = isr_table[IRQ_ARM_TIMER].param;
isr_func(IRQ_ARM_TIMER, param);
}
}
}
}
/* local interrupt*/
if (value)
{
if (value & (1 << 8))
{
value = IRQ_PEND1;
irq = __rt_ffs(value) - 1;
}
else if (value & (1 << 9))
{
value = IRQ_PEND2;
irq = __rt_ffs(value) + 31;
}
else
{
value &= 0x0f;
irq = __rt_ffs(value) + 63;
}
/* get interrupt service routine */
isr_func = isr_table[irq].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[irq].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
param = isr_table[irq].param;
/* turn to interrupt service routine */
isr_func(irq, param);
}
}
#else
void *param;
int ir, ir_real;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
ir_real = ir & 0x3ff;
if (ir == 1023)
{
/* Spurious interrupt */
return;
}
/* get interrupt service routine */
isr_func = isr_table[ir_real].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[ir_real].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
param = isr_table[ir_real].param;
/* turn to interrupt service routine */
isr_func(ir, param);
}
/* end of interrupt */
rt_hw_interrupt_ack(ir);
#endif
}
void rt_hw_trap_fiq(void)
{
void *param;
int ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
/* get interrupt service routine */
isr_func = isr_table[ir].handler;
param = isr_table[ir].param;
/* turn to interrupt service routine */
isr_func(ir, param);
/* end of interrupt */
rt_hw_interrupt_ack(ir);
}
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
#include "rtconfig.h"
.section .vectors, "ax"
.code 32
.globl system_vectors
system_vectors:
#ifdef RT_USING_SMART
b _reset
#else
ldr pc, _vector_reset
#endif
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
ldr pc, _vector_dabt
ldr pc, _vector_resv
ldr pc, _vector_irq
ldr pc, _vector_fiq
.globl _reset
.globl vector_undef
.globl vector_swi
.globl vector_pabt
.globl vector_dabt
.globl vector_resv
.globl vector_irq
.globl vector_fiq
_vector_reset:
.word _reset
_vector_undef:
.word vector_undef
_vector_swi:
.word vector_swi
_vector_pabt:
.word vector_pabt
_vector_dabt:
.word vector_dabt
_vector_resv:
.word vector_resv
_vector_irq:
.word vector_irq
_vector_fiq:
.word vector_fiq
.balignl 16,0xdeadbeef