summaryrefslogtreecommitdiff
path: root/libcpu/arm
diff options
context:
space:
mode:
authorguo <[email protected]>2022-12-03 12:07:44 +0800
committerGitHub <[email protected]>2022-12-03 12:07:44 +0800
commitecf2d8215961ca7c539132b62a72df6072cc3e14 (patch)
tree59005f0f74f2593c0435059264f624c862a89f55 /libcpu/arm
parentaaf5462c6d4ae9466a0a8cd2a4bb00cfe1fef2f2 (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')
-rw-r--r--libcpu/arm/am335x/cpuport.h23
-rw-r--r--libcpu/arm/arm926/cpuport.h13
-rw-r--r--libcpu/arm/common/backtrace.c63
-rw-r--r--libcpu/arm/cortex-a/SConscript4
-rw-r--r--libcpu/arm/cortex-a/backtrace.c545
-rw-r--r--libcpu/arm/cortex-a/backtrace.h83
-rw-r--r--libcpu/arm/cortex-a/cache.c50
-rw-r--r--libcpu/arm/cortex-a/context_gcc.S101
-rw-r--r--libcpu/arm/cortex-a/cp15_gcc.S8
-rw-r--r--libcpu/arm/cortex-a/cpuport.c (renamed from libcpu/arm/cortex-a/cpu.c)11
-rw-r--r--libcpu/arm/cortex-a/cpuport.h (renamed from libcpu/arm/cortex-a/armv7.h)38
-rw-r--r--libcpu/arm/cortex-a/gic.c6
-rw-r--r--libcpu/arm/cortex-a/interrupt.c10
-rw-r--r--libcpu/arm/cortex-a/mmu.c675
-rw-r--r--libcpu/arm/cortex-a/mmu.h66
-rw-r--r--libcpu/arm/cortex-a/pmu.c8
-rw-r--r--libcpu/arm/cortex-a/stack.c4
-rw-r--r--libcpu/arm/cortex-a/start_gcc.S579
-rw-r--r--libcpu/arm/cortex-a/trap.c274
-rw-r--r--libcpu/arm/cortex-a/vector_gcc.S6
-rw-r--r--libcpu/arm/cortex-m4/cpuport.h23
-rw-r--r--libcpu/arm/cortex-m7/cpuport.h23
-rw-r--r--libcpu/arm/s3c24x0/cpuport.h23
-rw-r--r--libcpu/arm/zynqmp-r5/cpuport.h23
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(&regs, 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__*/