diff options
| author | guo <[email protected]> | 2022-12-03 12:07:44 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-12-03 12:07:44 +0800 |
| commit | ecf2d8215961ca7c539132b62a72df6072cc3e14 (patch) | |
| tree | 59005f0f74f2593c0435059264f624c862a89f55 /libcpu/arm | |
| parent | aaf5462c6d4ae9466a0a8cd2a4bb00cfe1fef2f2 (diff) | |
sync branch rt-smart. (#6641)
* Synchronize the code of the rt mart branch to the master branch.
* TTY device
* Add lwP code from rt-smart
* Add vnode in DFS, but DFS will be re-write for rt-smart
* There are three libcpu for rt-smart:
* arm/cortex-a, arm/aarch64
* riscv64
Co-authored-by: Rbb666 <[email protected]>
Co-authored-by: zhkag <[email protected]>
Diffstat (limited to 'libcpu/arm')
24 files changed, 2250 insertions, 409 deletions
diff --git a/libcpu/arm/am335x/cpuport.h b/libcpu/arm/am335x/cpuport.h new file mode 100644 index 0000000000..05bb12cf2f --- /dev/null +++ b/libcpu/arm/am335x/cpuport.h @@ -0,0 +1,23 @@ +/* + * 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__ + +#ifdef RT_USING_SMP +typedef union { + unsigned long slock; + struct __arch_tickets { + unsigned short owner; + unsigned short next; + } tickets; +} rt_hw_spinlock_t; +#endif + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/arm926/cpuport.h b/libcpu/arm/arm926/cpuport.h new file mode 100644 index 0000000000..b5dae0b0e0 --- /dev/null +++ b/libcpu/arm/arm926/cpuport.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef CPUPORT_H__ +#define CPUPORT_H__ + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/common/backtrace.c b/libcpu/arm/common/backtrace.c deleted file mode 100644 index bf3526703e..0000000000 --- a/libcpu/arm/common/backtrace.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2008-07-29 Bernard first version from QiuYi implementation - */ - -#include <rtthread.h> - -#ifdef __GNUC__ -/* --->High Address,Stack Top -PC<------| -LR | -IP | -FP | -...... | -PC <-| | -LR | | -IP | | -FP---|-- | -...... | -PC | -LR | -IP | -FP--- --->Low Address,Stack Bottom -*/ -void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry) -{ - rt_uint32_t i, pc, func_entry; - - pc = *fp; - rt_kprintf("[0x%x]\n", pc - 0xC); - - for (i = 0; i < 10; i++) - { - fp = (rt_uint32_t *) * (fp - 3); - pc = *fp ; - - func_entry = pc - 0xC; - - if (func_entry <= 0x30000000) break; - - if (func_entry == thread_entry) - { - rt_kprintf("EntryPoint:0x%x\n", func_entry); - - break; - } - - rt_kprintf("[0x%x]\n", func_entry); - } -} -#else -void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry) -{ - /* old compiler implementation */ -} -#endif diff --git a/libcpu/arm/cortex-a/SConscript b/libcpu/arm/cortex-a/SConscript index 6075a8622c..562c6ffa4f 100644 --- a/libcpu/arm/cortex-a/SConscript +++ b/libcpu/arm/cortex-a/SConscript @@ -7,12 +7,12 @@ Import('rtconfig') cwd = GetCurrentDir() src = Split(''' cache.c -cpu.c +cpuport.c gtimer.c mmu.c pmu.c stack.c - +backtrace.c ''') CPPPATH = [cwd] diff --git a/libcpu/arm/cortex-a/backtrace.c b/libcpu/arm/cortex-a/backtrace.c new file mode 100644 index 0000000000..1d4d444aa9 --- /dev/null +++ b/libcpu/arm/cortex-a/backtrace.c @@ -0,0 +1,545 @@ +#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_USERSPACE +#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; +} + +/* Dummy functions to avoid linker complaints */ +void __aeabi_unwind_cpp_pr0(void) +{ +}; + +void __aeabi_unwind_cpp_pr1(void) +{ +}; + +void __aeabi_unwind_cpp_pr2(void) +{ +}; + +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_USERSPACE + 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); +} + +void rt_backtrace(void) +{ + struct rt_hw_exp_stack regs; + + asm volatile ("mov %0, fp":"=r"(regs.fp)); + asm volatile ("mov %0, sp":"=r"(regs.sp)); + asm volatile ("mov %0, lr":"=r"(regs.lr)); + asm volatile ("mov %0, pc":"=r"(regs.pc)); + rt_unwind(®s, 8); +} + diff --git a/libcpu/arm/cortex-a/backtrace.h b/libcpu/arm/cortex-a/backtrace.h new file mode 100644 index 0000000000..a6ed226094 --- /dev/null +++ b/libcpu/arm/cortex-a/backtrace.h @@ -0,0 +1,83 @@ +#ifndef __BACKTRACE_H +#define __BACKTRACE_H + +#ifndef __ASSEMBLY__ +#include <cpuport.h> + +/* Unwind reason code according the the ARM EABI documents */ +enum unwind_reason_code +{ + URC_OK = 0, /* operation completed successfully */ + URC_CONTINUE_UNWIND = 8, + URC_FAILURE = 9 /* unspecified failure of some kind */ +}; + +struct unwind_idx +{ + unsigned long addr_offset; + unsigned long insn; +}; + +struct unwind_table +{ + const struct unwind_idx *start; + const struct unwind_idx *origin; + const struct unwind_idx *stop; + unsigned long begin_addr; + unsigned long end_addr; +}; + +struct stackframe +{ + /* + * FP member should hold R7 when CONFIG_THUMB2_KERNEL is enabled + * and R11 otherwise. + */ + unsigned long fp; + unsigned long sp; + unsigned long lr; + unsigned long pc; +}; + +struct pt_regs +{ + unsigned long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +#define instruction_pointer(regs) (regs)->ARM_pc + +#ifdef CONFIG_THUMB2_KERNEL +#define frame_pointer(regs) (regs)->ARM_r7 +#else +#define frame_pointer(regs) (regs)->ARM_fp +#endif + +int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]); +void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]); + +void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj); +void rt_backtrace(void); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __BACKTRACE_H */ + diff --git a/libcpu/arm/cortex-a/cache.c b/libcpu/arm/cortex-a/cache.c index a6b59182a6..c243e8e358 100644 --- a/libcpu/arm/cortex-a/cache.c +++ b/libcpu/arm/cortex-a/cache.c @@ -31,8 +31,8 @@ void rt_hw_cpu_icache_invalidate(void *addr, int size) 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); + 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 */ @@ -48,8 +48,8 @@ void rt_hw_cpu_dcache_invalidate(void *addr, int size) 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); + 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 */ @@ -96,8 +96,8 @@ void rt_hw_cpu_dcache_clean(void *addr, int size) 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); + 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 */ @@ -106,18 +106,19 @@ void rt_hw_cpu_dcache_clean(void *addr, int size) asm volatile ("dsb":::"memory"); } -void rt_hw_cpu_dcache_clean_inv(void *addr, int size) +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); + start_addr &= ~(line_size - 1); + end_addr &= ~(line_size - 1); while (start_addr < end_addr) { - asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr)); + 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"); @@ -126,15 +127,21 @@ void rt_hw_cpu_dcache_clean_inv(void *addr, int size) 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) @@ -146,3 +153,26 @@ rt_base_t rt_hw_cpu_dcache_status(void) { return 0; } + +#ifdef RT_USING_LWP +#define ICACHE (1<<0) +#define DCACHE (1<<1) +#define BCACHE (ICACHE|DCACHE) + +int sys_cacheflush(void *addr, int size, int cache) +{ + if ((size_t)addr < KERNEL_VADDR_START && (size_t)addr + size <= KERNEL_VADDR_START) + { + if ((cache & DCACHE) != 0) + { + rt_hw_cpu_dcache_clean_and_invalidate(addr, size); + } + if ((cache & ICACHE) != 0) + { + rt_hw_cpu_icache_invalidate(addr, size); + } + return 0; + } + return -1; +} +#endif diff --git a/libcpu/arm/cortex-a/context_gcc.S b/libcpu/arm/cortex-a/context_gcc.S index 768c5138e9..77ca0a7aa2 100644 --- a/libcpu/arm/cortex-a/context_gcc.S +++ b/libcpu/arm/cortex-a/context_gcc.S @@ -45,7 +45,20 @@ rt_hw_context_switch_to: #ifdef RT_USING_SMP mov r0, r1 bl rt_cpus_lock_status_restore +#ifdef RT_USING_USERSPACE + bl rt_thread_self + bl lwp_user_setting_restore +#endif +#else +#ifdef RT_USING_USERSPACE + bl rt_thread_self + mov r4, r0 + bl lwp_mmu_switch + mov r0, r4 + bl lwp_user_setting_restore +#endif #endif /*RT_USING_SMP*/ + b rt_hw_context_switch_exit .section .bss.share.isr @@ -95,7 +108,20 @@ rt_hw_context_switch: #ifdef RT_USING_SMP mov r0, r2 bl rt_cpus_lock_status_restore +#ifdef RT_USING_USERSPACE + bl rt_thread_self + bl lwp_user_setting_restore +#endif +#else +#ifdef RT_USING_USERSPACE + bl rt_thread_self + mov r4, r0 + bl lwp_mmu_switch + mov r0, r4 + bl lwp_user_setting_restore +#endif #endif /*RT_USING_SMP*/ + b rt_hw_context_switch_exit /* @@ -123,28 +149,69 @@ rt_hw_context_switch_interrupt: * r2 :addr of to_thread's sp * r3 :to_thread's tcb */ - +#ifdef RT_USING_LWP + push {r0 - r3, lr} +#ifdef RT_USING_USERSPACE + 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_USERSPACE + mov r4, r0 +#endif bl rt_cpus_lock_status_restore - +#ifdef RT_USING_USERSPACE + mov r0, r4 + bl lwp_user_setting_restore +#endif b rt_hw_context_switch_exit #else /*RT_USING_SMP*/ - ldr r2, =rt_thread_switch_interrupt_flag - ldr r3, [r2] + /* 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_LWP + /* 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_USERSPACE + 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 ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread + 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 r0, [ip] - str r3, [r2] + str r3, [ip] _reswitch: - ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread - str r1, [r2] + 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 @@ -178,5 +245,21 @@ rt_hw_context_switch_exit: #endif ldmfd sp!, {r1} msr spsr_cxsf, r1 /* original mode */ + +#ifdef RT_USING_LWP + 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 diff --git a/libcpu/arm/cortex-a/cp15_gcc.S b/libcpu/arm/cortex-a/cp15_gcc.S index 983ae522ef..dd2436ffee 100644 --- a/libcpu/arm/cortex-a/cp15_gcc.S +++ b/libcpu/arm/cortex-a/cp15_gcc.S @@ -8,11 +8,9 @@ * 2013-07-05 Bernard the first version */ -.weak rt_hw_cpu_id -rt_hw_cpu_id: - mrc p15, #0, r0, c0, c0, #5 @ read multiprocessor affinity register - ldr r1, =0xFFFF03 @ Affinity mask off, leaving CPU ID field, [0:1]CPU ID, [8:15]Cluster ID Aff1, [16:23]Cluster ID Aff2 - and r0, r0, r1 +.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 diff --git a/libcpu/arm/cortex-a/cpu.c b/libcpu/arm/cortex-a/cpuport.c index 7d1a389f08..aea3b88f00 100644 --- a/libcpu/arm/cortex-a/cpu.c +++ b/libcpu/arm/cortex-a/cpuport.c @@ -13,6 +13,17 @@ #include <rtthread.h> #include <board.h> +int rt_hw_cpu_id(void) +{ + int cpu_id; + __asm__ volatile ( + "mrc p15, 0, %0, c0, c0, 5" + :"=r"(cpu_id) + ); + cpu_id &= 0xf; + return cpu_id; +} + #ifdef RT_USING_SMP void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock) diff --git a/libcpu/arm/cortex-a/armv7.h b/libcpu/arm/cortex-a/cpuport.h index 325d0ed0ae..ab68d1e311 100644 --- a/libcpu/arm/cortex-a/armv7.h +++ b/libcpu/arm/cortex-a/cpuport.h @@ -1,13 +1,14 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2020, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes */ -#ifndef __ARMV7_H__ -#define __ARMV7_H__ + +#ifndef CPUPORT_H__ +#define CPUPORT_H__ /* the exception stack without VFP registers */ struct rt_hw_exp_stack @@ -69,10 +70,29 @@ struct rt_hw_stack #define E_Bit (1<<9) #define J_Bit (1<<24) -#define PABT_EXCEPTION 0x1 -#define DABT_EXCEPTION 0x2 -#define UND_EXCEPTION 0x3 -#define SWI_EXCEPTION 0x4 -#define RESV_EXCEPTION 0xF - +#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"); +} + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/cortex-a/gic.c b/libcpu/arm/cortex-a/gic.c index 5dda22530d..e65bb5413e 100644 --- a/libcpu/arm/cortex-a/gic.c +++ b/libcpu/arm/cortex-a/gic.c @@ -431,7 +431,11 @@ int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base) { RT_ASSERT(index < ARM_GIC_MAX_NR); - _gic_table[index].cpu_hw_base = cpu_base; + 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; diff --git a/libcpu/arm/cortex-a/interrupt.c b/libcpu/arm/cortex-a/interrupt.c index f90f1c0094..6cf7362554 100644 --- a/libcpu/arm/cortex-a/interrupt.c +++ b/libcpu/arm/cortex-a/interrupt.c @@ -69,8 +69,13 @@ void rt_hw_interrupt_init(void) rt_memset(isr_table, 0x00, sizeof(isr_table)); /* initialize ARM GIC */ +#ifdef RT_USING_USERSPACE + gic_dist_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_dist_base(), 0x2000, MMU_MAP_K_RW); + gic_cpu_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_cpu_base(), 0x1000, MMU_MAP_K_RW); +#else gic_dist_base = platform_get_gic_dist_base(); gic_cpu_base = platform_get_gic_cpu_base(); +#endif gic_irq_start = GIC_IRQ_START; @@ -94,7 +99,12 @@ void rt_hw_interrupt_init(void) rt_memset(isr_table, 0x00, sizeof(isr_table)); /* initialize ARM GIC */ +#ifdef RT_USING_USERSPACE + gic_dist_base = (uint32_t)rt_hw_mmu_map(&mmu_info, 0, (void*)platform_get_gic_dist_base(), 0x2000, MMU_MAP_K_RW); +#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); diff --git a/libcpu/arm/cortex-a/mmu.c b/libcpu/arm/cortex-a/mmu.c index 243fe19a0a..47f7676ace 100644 --- a/libcpu/arm/cortex-a/mmu.c +++ b/libcpu/arm/cortex-a/mmu.c @@ -8,13 +8,67 @@ * 2012-01-10 bernard porting to AM1808 */ -#include <rtthread.h> #include <rthw.h> +#include <rtthread.h> + #include <board.h> #include "cp15.h" #include "mmu.h" +#ifdef RT_USING_LWP +#include <lwp_mm.h> +#include "page.h" +#endif + +/* level1 page table, each entry for 1MB memory. */ +volatile unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); + +#ifndef RT_USING_LWP +static rt_mutex_t mm_lock = RT_NULL; + +void rt_mm_lock(void) +{ + if (rt_thread_self()) + { + if (!mm_lock) + { + mm_lock = rt_mutex_create("mm_lock", RT_IPC_FLAG_FIFO); + } + if (mm_lock) + { + rt_mutex_take(mm_lock, RT_WAITING_FOREVER); + } + } +} + +void rt_mm_unlock(void) +{ + if (rt_thread_self()) + { + if (mm_lock) + { + rt_mutex_release(mm_lock); + } + } +} +#endif + +void rt_hw_cpu_tlb_invalidate(void) +{ + asm volatile ("mcr p15, 0, r0, c8, c7, 0\ndsb\nisb" ::: "memory"); +} + +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; +} + /* dump 2nd level page table */ void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) { @@ -122,8 +176,6 @@ void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) } } -/* level1 page table, each entry for 1MB memory. */ -volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd, rt_uint32_t paddrStart, @@ -140,16 +192,6 @@ void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, } } -unsigned long rt_hw_set_domain_register(unsigned long domain_val) -{ - unsigned long old_domain; - - asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); - asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); - - return old_domain; -} - void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size) { /* set page table */ @@ -159,6 +201,8 @@ void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size) 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) @@ -180,3 +224,608 @@ void rt_hw_mmu_init(void) rt_hw_cpu_dcache_enable(); } +int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off) +{ + size_t l1_off, va_s, va_e; + + if (!mmu_info || !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; + } + } + + mmu_info->vtable = vtable; + mmu_info->vstart = va_s; + mmu_info->vend = va_e; + mmu_info->pv_off = pv_off; + + return 0; +} + +int rt_hw_mmu_ioremap_init(rt_mmu_info *mmu_info, 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*)mmu_info->vtable + 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 + mmu_info->pv_off) | 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; +} + +#ifdef RT_USING_LWP +static size_t find_vaddr(rt_mmu_info *mmu_info, int pages) +{ + size_t l1_off, l2_off; + size_t *mmu_l1, *mmu_l2; + size_t find_off = 0; + size_t find_va = 0; + int n = 0; + + if (!pages) + { + return 0; + } + + if (!mmu_info) + { + return 0; + } + + for (l1_off = mmu_info->vstart; l1_off <= mmu_info->vend; l1_off++) + { + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + if (*mmu_l1 & ARCH_MMU_USED_MASK) + { + mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off); + for (l2_off = 0; l2_off < (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE); l2_off++) + { + if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK) + { + /* in use */ + n = 0; + } + else + { + if (!n) + { + find_va = l1_off; + find_off = l2_off; + } + n++; + if (n >= pages) + { + return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT); + } + } + } + } + else + { + if (!n) + { + find_va = l1_off; + find_off = 0; + } + n += (ARCH_SECTION_SIZE/ARCH_PAGE_SIZE); + if (n >= pages) + { + return (find_va << ARCH_SECTION_SHIFT) + (find_off << ARCH_PAGE_SHIFT); + } + } + } + return 0; +} + +static int check_vaddr(rt_mmu_info *mmu_info, void *va, int pages) +{ + size_t loop_va = (size_t)va & ~ARCH_PAGE_MASK; + size_t l1_off, l2_off; + size_t *mmu_l1, *mmu_l2; + + if (!pages) + { + return -1; + } + + if (!mmu_info) + { + return -1; + } + + l1_off = ((size_t)va >> ARCH_SECTION_SHIFT); + if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend) + { + return -1; + } + l1_off += ((pages << ARCH_PAGE_SHIFT) >> ARCH_SECTION_SHIFT); + if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend + 1) + { + return -1; + } + + while (pages--) + { + l1_off = (loop_va >> ARCH_SECTION_SHIFT); + l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT); + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + + if (*mmu_l1 & ARCH_MMU_USED_MASK) + { + mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off); + if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK) + { + return -1; + } + } + loop_va += ARCH_PAGE_SIZE; + } + return 0; +} + +static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t npages) +{ + size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK; + size_t l1_off, l2_off; + size_t *mmu_l1, *mmu_l2; + + if (!mmu_info) + { + return; + } + + while (npages--) + { + l1_off = (loop_va >> ARCH_SECTION_SHIFT); + if (l1_off < mmu_info->vstart || l1_off > mmu_info->vend) + { + return; + } + + l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT); + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + + if (*mmu_l1 & ARCH_MMU_USED_MASK) + { + mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off); + } + 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 __rt_hw_mmu_map(rt_mmu_info *mmu_info, void* v_addr, void* p_addr, size_t npages, 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; + + if (!mmu_info) + { + return -1; + } + + while (npages--) + { + l1_off = (loop_va >> ARCH_SECTION_SHIFT); + l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT); + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + + if (*mmu_l1 & ARCH_MMU_USED_MASK) + { + mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off); + 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 + mmu_info->pv_off) | 0x1); + /* cache maintain */ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4); + } + else + { + /* error, unmap and quit */ + __rt_hw_mmu_unmap(mmu_info, v_addr, npages); + 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_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr) +{ + size_t pa_s, pa_e; + size_t vaddr; + int pages; + int ret; + + if (!size) + { + return 0; + } + pa_s = (size_t)p_addr; + pa_e = (size_t)p_addr + size - 1; + pa_s >>= ARCH_PAGE_SHIFT; + pa_e >>= ARCH_PAGE_SHIFT; + pages = pa_e - pa_s + 1; + if (v_addr) + { + vaddr = (size_t)v_addr; + pa_s = (size_t)p_addr; + if ((vaddr & ARCH_PAGE_MASK) != (pa_s & ARCH_PAGE_MASK)) + { + return 0; + } + vaddr &= ~ARCH_PAGE_MASK; + if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0) + { + return 0; + } + } + else + { + vaddr = find_vaddr(mmu_info, pages); + } + if (vaddr) { + rt_enter_critical(); + ret = __rt_hw_mmu_map(mmu_info, (void*)vaddr, p_addr, pages, attr); + if (ret == 0) + { + rt_hw_cpu_tlb_invalidate(); + rt_exit_critical(); + return (void*)(vaddr + ((size_t)p_addr & ARCH_PAGE_MASK)); + } + rt_exit_critical(); + } + return 0; +} + +static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void* v_addr, size_t npages, size_t attr) +{ + size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK; + size_t loop_pa; + size_t l1_off, l2_off; + size_t *mmu_l1, *mmu_l2; + + if (!mmu_info) + { + return -1; + } + + while (npages--) + { + loop_pa = (size_t)rt_pages_alloc(0); + if (!loop_pa) + goto err; + + l1_off = (loop_va >> ARCH_SECTION_SHIFT); + l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT); + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + + if (*mmu_l1 & ARCH_MMU_USED_MASK) + { + mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - mmu_info->pv_off); + rt_page_ref_inc(mmu_l2, 0); + } + else + { + //mmu_l2 = (size_t*)rt_malloc_align(ARCH_PAGE_TBL_SIZE * 2, ARCH_PAGE_TBL_SIZE); + 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 + mmu_info->pv_off) | 0x1); + /* cache maintain */ + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4); + } + else + goto err; + } + + loop_pa += mmu_info->pv_off; + *(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; + } + return 0; +err: + { + /* error, unmap and quit */ + int i; + void *va, *pa; + + va = (void*)((size_t)v_addr & ~ARCH_PAGE_MASK); + for (i = 0; i < npages; i++) + { + pa = rt_hw_mmu_v2p(mmu_info, va); + pa = (void*)((char*)pa - mmu_info->pv_off); + rt_pages_free(pa, 0); + va = (void*)((char*)va + ARCH_PAGE_SIZE); + } + + __rt_hw_mmu_unmap(mmu_info, v_addr, npages); + return -1; + } +} + +void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr) +{ + size_t vaddr; + size_t offset; + int pages; + int ret; + + if (!size) + { + return 0; + } + + offset = (size_t)v_addr & ARCH_PAGE_MASK; + size += (offset + ARCH_PAGE_SIZE - 1); + pages = (size >> ARCH_PAGE_SHIFT); + if (v_addr) + { + vaddr = (size_t)v_addr; + vaddr &= ~ARCH_PAGE_MASK; + if (check_vaddr(mmu_info, (void*)vaddr, pages) != 0) + { + return 0; + } + } + else + { + vaddr = find_vaddr(mmu_info, pages); + } + + if (vaddr) + { + rt_enter_critical(); + ret = __rt_hw_mmu_map_auto(mmu_info, (void*)vaddr, pages, attr); + if (ret == 0) + { + rt_hw_cpu_tlb_invalidate(); + rt_exit_critical(); + return (void*)((char*)vaddr + offset); + } + rt_exit_critical(); + } + return 0; +} + +void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size) +{ + size_t va_s, va_e; + int pages; + + va_s = (size_t)v_addr; + va_e = (size_t)v_addr + size - 1; + va_s >>= ARCH_PAGE_SHIFT; + va_e >>= ARCH_PAGE_SHIFT; + pages = va_e - va_s + 1; + rt_enter_critical(); + __rt_hw_mmu_unmap(mmu_info, v_addr, pages); + rt_hw_cpu_tlb_invalidate(); + rt_exit_critical(); +} + +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr) +{ + void *ret; + + rt_mm_lock(); + ret = _rt_hw_mmu_map(mmu_info, v_addr, p_addr, size, attr); + rt_mm_unlock(); + return ret; +} + +void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr) +{ + void *ret; + + rt_mm_lock(); + ret = _rt_hw_mmu_map_auto(mmu_info, v_addr, size, attr); + rt_mm_unlock(); + return ret; +} + +void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size) +{ + rt_mm_lock(); + _rt_hw_mmu_unmap(mmu_info, v_addr, size); + rt_mm_unlock(); +} + +void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, 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; + + if (!mmu_info) + { + return (void*)0; + } + + mmu_l1 = (size_t*)mmu_info->vtable + 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) - mmu_info->pv_off); + 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 (void*)0; +} + +void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr) +{ + void *ret; + + rt_mm_lock(); + ret = _rt_hw_mmu_v2p(mmu_info, v_addr); + rt_mm_unlock(); + return ret; +} + +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; + } + } +} +#endif diff --git a/libcpu/arm/cortex-a/mmu.h b/libcpu/arm/cortex-a/mmu.h index 5cc60a774d..0bd80dd06c 100644 --- a/libcpu/arm/cortex-a/mmu.h +++ b/libcpu/arm/cortex-a/mmu.h @@ -19,8 +19,14 @@ #define SHAREDEVICE (1<<2) /* shared device */ #define STRONGORDER (0<<2) /* strong ordered */ #define XN (1<<4) /* eXecute Never */ +#ifdef RT_USING_USERSPACE +#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 */ +#define AP_RO ((2<<10) /* supervisor=RW, user=RO */ +#endif + #define SHARED (1<<16) /* shareable */ #define DOMAIN_FAULT (0x0) @@ -37,6 +43,8 @@ /* 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; @@ -45,5 +53,61 @@ struct mem_desc rt_uint32_t attr; }; +#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_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_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 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 + +typedef struct +{ + size_t *vtable; + size_t vstart; + size_t vend; + size_t pv_off; +} rt_mmu_info; + +int rt_hw_mmu_map_init(rt_mmu_info *mmu_info, void* v_address, size_t size, size_t *vtable, size_t pv_off); +int rt_hw_mmu_ioremap_init(rt_mmu_info *mmu_info, void* v_address, size_t size); +void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size); + +#ifdef RT_USING_USERSPACE +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void *v_addr, void* p_addr, size_t size, size_t attr); +void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info, void *v_addr, size_t size, size_t attr); +#else +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr); +#endif + +void rt_hw_mmu_unmap(rt_mmu_info *mmu_info, void* v_addr, size_t size); +void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void* v_addr); #endif diff --git a/libcpu/arm/cortex-a/pmu.c b/libcpu/arm/cortex-a/pmu.c index 2b9165cc8b..4b62849a1a 100644 --- a/libcpu/arm/cortex-a/pmu.c +++ b/libcpu/arm/cortex-a/pmu.c @@ -9,12 +9,16 @@ #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(); - rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n", - reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f); + 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)); } diff --git a/libcpu/arm/cortex-a/stack.c b/libcpu/arm/cortex-a/stack.c index e68b324867..875794bade 100644 --- a/libcpu/arm/cortex-a/stack.c +++ b/libcpu/arm/cortex-a/stack.c @@ -9,11 +9,11 @@ * 2011-10-05 Bernard add thumb mode */ #include <rtthread.h> +#include <cpuport.h> #include <board.h> -#include <armv7.h> /** - * @addtogroup AM33xx + * @addtogroup ARM Cortex-A */ /*@{*/ diff --git a/libcpu/arm/cortex-a/start_gcc.S b/libcpu/arm/cortex-a/start_gcc.S index 5916ddf957..5ddb7311a8 100644 --- a/libcpu/arm/cortex-a/start_gcc.S +++ b/libcpu/arm/cortex-a/start_gcc.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2022, RT-Thread Development Team + * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -19,40 +19,15 @@ .equ Mode_UND, 0x1B .equ Mode_SYS, 0x1F -.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled -.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled +.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */ +.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */ -.equ UND_Stack_Size, 0x00000400 -.equ SVC_Stack_Size, 0x00000400 -.equ ABT_Stack_Size, 0x00000400 -.equ RT_FIQ_STACK_PGSZ, 0x00000000 -.equ RT_IRQ_STACK_PGSZ, 0x00000800 -.equ USR_Stack_Size, 0x00000400 - -.equ SUB_UND_Stack_Size, 0x00000400 -.equ SUB_SVC_Stack_Size, 0x00000400 -.equ SUB_ABT_Stack_Size, 0x00000400 -.equ SUB_RT_FIQ_STACK_PGSZ, 0x00000000 -.equ SUB_RT_IRQ_STACK_PGSZ, 0x00000400 -.equ SUB_USR_Stack_Size, 0x00000400 - -#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ - RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) - -#define SUB_ISR_Stack_Size (SUB_UND_Stack_Size + SUB_SVC_Stack_Size + SUB_ABT_Stack_Size + \ - SUB_RT_FIQ_STACK_PGSZ + SUB_RT_IRQ_STACK_PGSZ) - -.section .bss.share.isr -/* stack */ -.globl stack_start -.globl stack_top - -.align 3 -stack_start: -.rept ISR_Stack_Size -.byte 0 -.endr -stack_top: +#ifdef RT_USING_USERSPACE +.data +.align 14 +init_mtbl: + .space 16*1024 +#endif .text /* reset entry */ @@ -71,15 +46,96 @@ overHyped: /* Get out of HYP mode */ adr r1, continue msr ELR_hyp, r1 mrs r1, cpsr_all - and r1, r1, #0x1f ;@ CPSR_MODE_MASK - orr r1, r1, #0x13 ;@ CPSR_MODE_SUPERVISOR + and r1, r1, #0x1f /* CPSR_MODE_MASK */ + orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */ + msr SPSR_hyp, r1 + eret + +continue: +#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 + +overHyped: /* Get out of HYP mode */ + adr r1, continue + msr ELR_hyp, r1 + mrs r1, cpsr_all + and r1, r1, #0x1f /* CPSR_MODE_MASK */ + orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */ msr SPSR_hyp, r1 eret continue: + /* 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 + +#ifdef RT_USING_USERSPACE + ldr r5, =PV_OFFSET + + mov r7, #0x100000 + sub r7, #1 + mvn r8, r7 + + + ldr r9, =KERNEL_VADDR_START + + ldr r6, =__bss_end + add r6, r7 + and r6, r8 /* r6 end vaddr align up to 1M */ + sub r6, r9 /* r6 is size */ + + ldr sp, =svc_stack_n_limit + add sp, r5 /* use paddr */ + + ldr r0, =init_mtbl + add r0, r5 + mov r1, r6 + mov r2, r5 + bl init_mm_setup + + ldr lr, =after_enable_mmu + ldr r0, =init_mtbl + add r0, r5 + b enable_mmu + +after_enable_mmu: #endif +#ifndef SOC_BCM283x /* set the cpu to SVC32 mode and disable interrupt */ cps #Mode_SVC +#endif #ifdef RT_USING_FPU mov r4, #0xfffffff @@ -88,41 +144,9 @@ continue: /* disable the data alignment check */ mrc p15, 0, r1, c1, c0, 0 - bic r1, #(1<<0) /* Disable MMU */ - bic r1, #(1<<1) /* Disable Alignment fault checking */ - bic r1, #(1<<2) /* Disable data cache */ - bic r1, #(1<<11) /* Disable program flow prediction */ - bic r1, #(1<<12) /* Disable instruction cache */ - bic r1, #(3<<19) /* bit[20:19] must be zero */ + bic r1, #(1<<1) mcr p15, 0, r1, c1, c0, 0 - @ get cpu id, and subtract the offset from the stacks base address - bl rt_hw_cpu_id - mov r5, r0 - - cmp r5, #0 @ cpu id == 0 - beq normal_setup - - @ cpu id > 0, stop or wait -#ifdef RT_SMP_AUTO_BOOT - ldr r0, =secondary_cpu_entry - mov r1, #0 - str r1, [r0] /* clean secondary_cpu_entry */ -#endif /* RT_SMP_AUTO_BOOT */ - -secondary_loop: - @ cpu core 1 goes into sleep until core 0 wakeup it - wfe -#ifdef RT_SMP_AUTO_BOOT - ldr r1, =secondary_cpu_entry - ldr r0, [r1] - cmp r0, #0 - blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */ -#endif /* RT_SMP_AUTO_BOOT */ - b secondary_loop - -normal_setup: - /* enable I cache + branch prediction */ mrc p15, 0, r0, c1, c0, 0 orr r0, r0, #(1<<12) @@ -130,32 +154,53 @@ normal_setup: mcr p15, 0, r0, c1, c0, 0 /* setup stack */ - bl stack_setup + bl stack_setup /* clear .bss */ - mov r0,#0 /* get a zero */ - ldr r1,=__bss_start /* bss start */ - ldr r2,=__bss_end /* bss end */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ bss_loop: - cmp r1,r2 /* check if data to clear */ - strlo r0,[r1],#4 /* clear 4 bytes */ - blo bss_loop /* loop until done */ + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ #ifdef RT_USING_SMP mrc p15, 0, r1, c1, c0, 1 mov r0, #(1<<6) orr r1, r0 - mcr p15, 0, r1, c1, c0, 1 //enable smp + mcr p15, 0, r1, c1, c0, 1 /* enable smp */ #endif - /* initialize the mmu table and enable mmu */ ldr r0, =platform_mem_desc ldr r1, =platform_mem_desc_size ldr r1, [r1] bl rt_hw_init_mmu_table + +#ifdef RT_USING_USERSPACE + ldr r0, =MMUTable /* vaddr */ + add r0, r5 /* to paddr */ + bl rt_hw_mmu_switch +#else bl rt_hw_mmu_init +#endif + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: /* start RT-Thread Kernel */ ldr pc, _rtthread_startup @@ -163,37 +208,105 @@ _rtthread_startup: .word rtthread_startup stack_setup: - ldr r0, =stack_top - @ Set the startup stack for svc - mov sp, r0 - sub r0, r0, #SVC_Stack_Size +#ifdef RT_USING_SMP + /* cpu id */ + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #0xf + add r0, r0, #1 +#else + mov r0, #1 +#endif + + cps #Mode_UND + ldr r1, =und_stack_n + add sp, r1, r0, asl #12 - @ Enter Undefined Instruction Mode and set its Stack Pointer - msr cpsr_c, #Mode_UND|I_Bit|F_Bit - mov sp, r0 - sub r0, r0, #UND_Stack_Size + cps #Mode_IRQ + ldr r1, =irq_stack_n + add sp, r1, r0, asl #12 - @ Enter Abort Mode and set its Stack Pointer - msr cpsr_c, #Mode_ABT|I_Bit|F_Bit - mov sp, r0 - sub r0, r0, #ABT_Stack_Size + cps #Mode_FIQ + ldr r1, =irq_stack_n + add sp, r1, r0, asl #12 - @ Enter FIQ Mode and set its Stack Pointer - msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit - mov sp, r0 - sub r0, r0, #RT_FIQ_STACK_PGSZ + cps #Mode_ABT + ldr r1, =abt_stack_n + add sp, r1, r0, asl #12 - @ Enter IRQ Mode and set its Stack Pointer - msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit - mov sp, r0 - sub r0, r0, #RT_IRQ_STACK_PGSZ + cps #Mode_SVC + ldr r1, =svc_stack_n + add sp, r1, r0, asl #12 - /* come back to SVC mode */ - msr cpsr_c, #Mode_SVC|I_Bit|F_Bit bx lr -/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ +#ifdef RT_USING_USERSPACE +.align 2 +.global enable_mmu +enable_mmu: + orr r0, #0x18 + mcr p15, 0, r0, c2, c0, 0 /* ttbr0 */ + + mov r0, #(1 << 5) /* PD1=1 */ + mcr p15, 0, r0, c2, c0, 2 /* ttbcr */ + + mov r0, #1 + mcr p15, 0, r0, c3, c0, 0 /* dacr */ + + /* 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 + 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 + +.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 + +.global rt_hw_mmu_switch +rt_hw_mmu_switch: + mov r3, #0 + mcr p15, 0, r3, c13, c0, 1 /* set contextid = 0, for synchronization*/ + isb + + orr r0, #0x18 + mcr p15, 0, r0, c2, c0, 0 /* ttbr0 */ + + isb + mov r1, r1, LSL #0x8 + and r2, r2, #0xff + orr r1, r1, r2 /* contextid.PROCID = pid, contextid.ASID = asid*/ + mcr p15, 0, r1, c13, c0, 1 /* set contextid = r1*/ + isb + + mcr p15, 0, r0, c7, c5, 0 /* iciallu */ + mcr p15, 0, r0, c7, c5, 6 /* bpiall */ + + dsb + isb + 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 +#endif + +_halt: + wfe + b _halt + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ .section .text.isr, "ax" .align 5 .globl vector_fiq @@ -226,7 +339,7 @@ vector_irq: cps #Mode_IRQ sub lr, #4 - stmfd r0!, {r1, lr} /* svc_lr, svc_pc */ + stmfd r0!, {r1, lr} /* svc_lr, svc_pc */ stmfd r0!, {r2 - r12} ldmfd sp!, {r1, r2} /* original r0, r1 */ stmfd r0!, {r1 - r2} @@ -234,8 +347,8 @@ vector_irq: stmfd r0!, {r1} #ifdef RT_USING_LWP - stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */ - sub r0, #8 + stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */ + sub r0, #8 #endif #ifdef RT_USING_FPU /* fpu context */ @@ -255,12 +368,13 @@ vector_irq: /* 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 - cps #Mode_SVC - mov sp, r8 mov r0, r8 bl rt_scheduler_do_irq_switch @@ -273,41 +387,69 @@ vector_irq: 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 + /* 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_LWP + 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 + mov r1, #0 /* clear flag */ str r1, [r0] - mov r1, sp @ r1 point to {r0-r3} in stack + 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 + 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. + /* 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 + stmfd sp!, {r2} /* push old task's pc */ + stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */ + ldmfd r1, {r1-r4} /* restore r0-r3 of the interrupt thread */ + stmfd sp!, {r1-r4} /* push old task's r0-r3 */ + stmfd sp!, {r0} /* push old task's cpsr */ #ifdef RT_USING_LWP - stmfd sp, {r13, r14}^ @push usr_sp, usr_lr - sub sp, #8 + stmfd sp, {r13, r14}^ /*push usr_sp, usr_lr */ + sub sp, #8 #endif + #ifdef RT_USING_FPU /* fpu context */ vmrs r6, fpexc @@ -323,16 +465,22 @@ rt_hw_context_switch_interrupt_do: ldr r4, =rt_interrupt_from_thread ldr r5, [r4] - str sp, [r5] @ store sp in preempted tasks's TCB + 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 + ldr sp, [r6] /* get new task's stack pointer */ - bl rt_interrupt_hook + bl rt_thread_self +#ifdef RT_USING_USERSPACE + mov r4, r0 + bl lwp_mmu_switch + mov r0, r4 + bl lwp_user_setting_restore +#endif #ifdef RT_USING_FPU -/* fpu context */ + /* fpu context */ ldmfd sp!, {r6} vmsr fpexc, r6 tst r6, #(1<<30) @@ -345,36 +493,43 @@ rt_hw_context_switch_interrupt_do: #endif #ifdef RT_USING_LWP - ldmfd sp, {r13, r14}^ @pop usr_sp, usr_lr + ldmfd sp, {r13, r14}^ /*pop usr_sp, usr_lr */ add sp, #8 #endif - ldmfd sp!, {r4} @ pop new task's cpsr to spsr + ldmfd sp!, {r4} /* pop new task's cpsr to spsr */ msr spsr_cxsf, r4 - ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr +#ifdef RT_USING_LWP + 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 */ + sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} /* Calling r0-r12 */ mov r0, sp - mrs r6, spsr @/* Save CPSR */ - str lr, [r0, #15*4] @/* Push PC */ - str r6, [r0, #16*4] @/* Push CPSR */ - mrs r5, cpsr @/* Save CPSR */ - - and r4, r6, #0x1F - cmp r4, #Mode_USR - moveq r6, #Mode_SYS - - orr r6, r6, #0x80 @/* Switch to previous mode, then save SP & PC */ - msr cpsr_c, r6 - str sp, [r0, #13*4] @/* Save calling SP */ - str lr, [r0, #14*4] @/* Save calling PC */ - - msr cpsr_c, r5 @/* Switch back to current mode */ + 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 @@ -388,9 +543,10 @@ vector_swi: .globl vector_undef vector_undef: push_svc_reg - cps #Mode_UND bl rt_hw_trap_undef + cps #Mode_UND #ifdef RT_USING_FPU + sub sp, sp, #17 * 4 ldr lr, [sp, #15*4] ldmia sp, {r0 - r12} add sp, sp, #17 * 4 @@ -402,15 +558,57 @@ vector_undef: .globl vector_pabt vector_pabt: push_svc_reg +#ifdef RT_USING_USERSPACE + /* 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_USERSPACE + /* 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 @@ -420,8 +618,26 @@ vector_resv: b . #ifdef RT_USING_SMP -.global secondary_cpu_start -secondary_cpu_start: +.global rt_hw_clz +rt_hw_clz: + clz r0, r0 + bx lr + +.global rt_secondary_cpu_entry +rt_secondary_cpu_entry: +#ifdef RT_USING_USERSPACE + ldr r5, =PV_OFFSET + + ldr lr, =after_enable_mmu_n + ldr r0, =init_mtbl + add r0, r5 + b enable_mmu + +after_enable_mmu_n: + ldr r0, =MMUTable + add r0, r5 + bl rt_hw_mmu_switch +#endif #ifdef RT_USING_FPU mov r4, #0xfffffff @@ -431,60 +647,37 @@ secondary_cpu_start: mrc p15, 0, r1, c1, c0, 1 mov r0, #(1<<6) orr r1, r0 - mcr p15, 0, r1, c1, c0, 1 //enable smp + mcr p15, 0, r1, c1, c0, 1 /* enable smp */ mrc p15, 0, r0, c1, c0, 0 bic r0, #(1<<13) mcr p15, 0, r0, c1, c0, 0 - /* enable branch prediction */ - mrc p15, 0, r0, c1, c0, 0 - orr r0, r0, #(1<<11) - mcr p15, 0, r0, c1, c0, 0 - - @ get cpu id, and subtract the offset from the stacks base address - bl rt_hw_cpu_id - sub r5, r0, #1 - - ldr r0, =SUB_ISR_Stack_Size - mul r0, r0, r5 @r0 = SUB_ISR_Stack_Size * (cpuid - 1) - ldr r1, =sub_stack_top - sub r0, r1, r0 @r0 = sub_stack_top - (SUB_ISR_Stack_Size * (cpuid - 1)) - - cps #Mode_SVC - mov sp, r0 - sub r0, r0, #SUB_SVC_Stack_Size - - cps #Mode_UND - mov sp, r0 - sub r0, r0, #SUB_UND_Stack_Size - - cps #Mode_ABT - mov sp, r0 - sub r0, r0, #SUB_ABT_Stack_Size - - cps #Mode_FIQ - mov sp, r0 - sub r0, r0, #SUB_RT_FIQ_STACK_PGSZ - - cps #Mode_IRQ - mov sp, r0 - sub r0, r0, #SUB_RT_IRQ_STACK_PGSZ - - cps #Mode_SVC + bl stack_setup /* initialize the mmu table and enable mmu */ +#ifndef RT_USING_USERSPACE bl rt_hw_mmu_init +#endif - b secondary_cpu_c_start + b rt_hw_secondary_cpu_bsp_start +#endif + +#ifndef RT_CPUS_NR +#define RT_CPUS_NR 1 +#endif .bss -.align 2 //align to 2~2=4 +.align 3 /* align to 2~3=8 */ +svc_stack_n: + .space (RT_CPUS_NR << 12) +svc_stack_n_limit: -.global sub_stack_top /* used for backtrace to calculate stack top of irq mode */ +irq_stack_n: + .space (RT_CPUS_NR << 12) -sub_stack_start: - .space (SUB_ISR_Stack_Size * (RT_CPUS_NR-1)) -sub_stack_top: +und_stack_n: + .space (RT_CPUS_NR << 12) -#endif +abt_stack_n: + .space (RT_CPUS_NR << 12) diff --git a/libcpu/arm/cortex-a/trap.c b/libcpu/arm/cortex-a/trap.c index e8b3c8f0ec..82bb6f2f78 100644 --- a/libcpu/arm/cortex-a/trap.c +++ b/libcpu/arm/cortex-a/trap.c @@ -11,26 +11,51 @@ #include <rtthread.h> #include <rthw.h> #include <board.h> +#include <backtrace.h> -#include "armv7.h" #include "interrupt.h" -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) +#ifdef RT_USING_FINSH extern long list_thread(void); #endif -static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; +#ifdef RT_USING_LWP +#include <lwp.h> +#include <lwp_arch.h> -/** - * This function set the hook, which is invoked on fault exception handling. - * - * @param exception_handle the exception handling hook function. - */ -void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context)) +#ifdef LWP_USING_CORE_DUMP +#include <lwp_core_dump.h> +#endif + +void sys_exit(int value); +void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info) { - rt_exception_hook = exception_handle; + 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(-1); + } } +int check_user_stack(struct rt_hw_exp_stack *regs) +{ + void* dfar = RT_NULL; + + asm volatile ("MRC p15, 0, %0, c6, c0, 0":"=r"(dfar)); + if (arch_expand_user_stack(dfar)) + { + regs->pc -= 8; + return 1; + } + return 0; +} +#endif + /** * this function will show registers of CPU * @@ -45,25 +70,18 @@ void rt_hw_show_register(struct rt_hw_exp_stack *regs) rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); rt_kprintf("cpsr:0x%08x\n", regs->cpsr); - if (rt_exception_hook != RT_NULL) +#ifdef RT_USING_USERSPACE { - rt_err_t result; - - result = rt_exception_hook(regs); - if (result == RT_EOK) return; + 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_hw_mmu_v2p(&mmu_info, (void *)v)); } -} - -void (*rt_trap_hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type); - -/** - * This function will set a hook function to trap handler. - * - * @param hook the hook function - */ -void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char *ex, unsigned int exception_type)) -{ - rt_trap_hook = hook; +#endif } /** @@ -74,49 +92,52 @@ void rt_hw_trap_set_hook(void (*hook)(struct rt_hw_exp_stack *regs, const char * * * @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 val; + 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; } - asm volatile ("vmrs %0, fpexc" : "=r"(val)::"memory"); - - if (!(val & 0x40000000)) + if ((ins & 0xe00) == 0xa00) { /* float ins */ - val = (1U << 30); - - asm volatile ("vmsr fpexc, %0"::"r"(val):"memory"); + set_fpexc(1U << 30); regs->pc = addr; return; } } #endif - - if (rt_trap_hook == RT_NULL) - { - rt_kprintf("undefined instruction:\n"); - rt_hw_show_register(regs); -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_thread(); +#ifdef RT_USING_LWP + check_user_fault(regs, 4, "User undefined instruction"); #endif - rt_hw_cpu_shutdown(); - } - else - { - rt_trap_hook(regs, "undefined instruction", UND_EXCEPTION); - } + 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(); } /** @@ -130,19 +151,12 @@ void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) */ void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) { - if (rt_trap_hook == RT_NULL) - { - rt_kprintf("software interrupt:\n"); - rt_hw_show_register(regs); -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_thread(); + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); #endif - rt_hw_cpu_shutdown(); - } - else - { - rt_trap_hook(regs, "software instruction", SWI_EXCEPTION); - } + rt_hw_cpu_shutdown(); } /** @@ -155,19 +169,20 @@ void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) */ void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) { - if (rt_trap_hook == RT_NULL) - { - rt_kprintf("prefetch abort:\n"); - rt_hw_show_register(regs); -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_thread(); -#endif - rt_hw_cpu_shutdown(); - } - else +#ifdef RT_USING_LWP + if (dbg_check_event(regs, 4)) { - rt_trap_hook(regs, "prefetch abort", PABT_EXCEPTION); + 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(); } /** @@ -180,19 +195,24 @@ void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) */ void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) { - if (rt_trap_hook == RT_NULL) +#ifdef RT_USING_LWP + if (dbg_check_event(regs, 8)) { - rt_kprintf("data abort:"); - rt_hw_show_register(regs); -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_thread(); -#endif - rt_hw_cpu_shutdown(); + return; } - else + if (check_user_stack(regs)) { - rt_trap_hook(regs, "data abort", DABT_EXCEPTION); + 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(); } /** @@ -204,32 +224,87 @@ void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) */ void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) { - if (rt_trap_hook == RT_NULL) - { - rt_kprintf("reserved trap:\n"); - rt_hw_show_register(regs); -#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) - list_thread(); + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); #endif - rt_hw_cpu_shutdown(); - } - else - { - rt_trap_hook(regs, "reserved trap", RESV_EXCEPTION); - } + rt_hw_cpu_shutdown(); } void rt_hw_trap_irq(void) { +#ifdef SOC_BCM283x + extern rt_uint8_t core_timer_flag; void *param; - int int_ack; - int ir; + 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; - int_ack = rt_hw_interrupt_get_irq(); + 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); + } + } + } + } - ir = int_ack & GIC_ACK_INTID_MASK; + /* 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 */ @@ -237,20 +312,21 @@ void rt_hw_trap_irq(void) } /* get interrupt service routine */ - isr_func = isr_table[ir].handler; + isr_func = isr_table[ir_real].handler; #ifdef RT_USING_INTERRUPT_INFO - isr_table[ir].counter++; + isr_table[ir_real].counter++; #endif if (isr_func) { /* Interrupt for myself. */ - param = isr_table[ir].param; + param = isr_table[ir_real].param; /* turn to interrupt service routine */ isr_func(ir, param); } /* end of interrupt */ - rt_hw_interrupt_ack(int_ack); + rt_hw_interrupt_ack(ir); +#endif } void rt_hw_trap_fiq(void) diff --git a/libcpu/arm/cortex-a/vector_gcc.S b/libcpu/arm/cortex-a/vector_gcc.S index 60d3c6cf1d..eb872db71f 100644 --- a/libcpu/arm/cortex-a/vector_gcc.S +++ b/libcpu/arm/cortex-a/vector_gcc.S @@ -7,13 +7,19 @@ * 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_USERSPACE + b _reset +#else ldr pc, _vector_reset +#endif ldr pc, _vector_undef ldr pc, _vector_swi ldr pc, _vector_pabt diff --git a/libcpu/arm/cortex-m4/cpuport.h b/libcpu/arm/cortex-m4/cpuport.h new file mode 100644 index 0000000000..05bb12cf2f --- /dev/null +++ b/libcpu/arm/cortex-m4/cpuport.h @@ -0,0 +1,23 @@ +/* + * 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__ + +#ifdef RT_USING_SMP +typedef union { + unsigned long slock; + struct __arch_tickets { + unsigned short owner; + unsigned short next; + } tickets; +} rt_hw_spinlock_t; +#endif + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/cortex-m7/cpuport.h b/libcpu/arm/cortex-m7/cpuport.h new file mode 100644 index 0000000000..05bb12cf2f --- /dev/null +++ b/libcpu/arm/cortex-m7/cpuport.h @@ -0,0 +1,23 @@ +/* + * 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__ + +#ifdef RT_USING_SMP +typedef union { + unsigned long slock; + struct __arch_tickets { + unsigned short owner; + unsigned short next; + } tickets; +} rt_hw_spinlock_t; +#endif + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/s3c24x0/cpuport.h b/libcpu/arm/s3c24x0/cpuport.h new file mode 100644 index 0000000000..05bb12cf2f --- /dev/null +++ b/libcpu/arm/s3c24x0/cpuport.h @@ -0,0 +1,23 @@ +/* + * 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__ + +#ifdef RT_USING_SMP +typedef union { + unsigned long slock; + struct __arch_tickets { + unsigned short owner; + unsigned short next; + } tickets; +} rt_hw_spinlock_t; +#endif + +#endif /*CPUPORT_H__*/ diff --git a/libcpu/arm/zynqmp-r5/cpuport.h b/libcpu/arm/zynqmp-r5/cpuport.h new file mode 100644 index 0000000000..05bb12cf2f --- /dev/null +++ b/libcpu/arm/zynqmp-r5/cpuport.h @@ -0,0 +1,23 @@ +/* + * 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__ + +#ifdef RT_USING_SMP +typedef union { + unsigned long slock; + struct __arch_tickets { + unsigned short owner; + unsigned short next; + } tickets; +} rt_hw_spinlock_t; +#endif + +#endif /*CPUPORT_H__*/ |
