diff options
| author | Bernard Xiong <[email protected]> | 2020-01-16 15:43:07 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-01-16 15:43:07 +0800 |
| commit | 54814c42e7d3073d3b386245a1f04a8a347d7636 (patch) | |
| tree | b0175d9c60460767830d7faf455d1d7f0e67a1e3 /libcpu | |
| parent | b08d699e38a10dec0a9e0fa6367fd3da1b3d5793 (diff) | |
| parent | 317e5bf4a4a66572d7675601bf424226af1314ce (diff) | |
Merge pull request #3324 from bigmagic123/bsp_raspi
Bsp raspi
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/aarch64/SConscript | 16 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/SConscript | 15 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/armv8.h | 63 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/context_gcc.S | 312 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/cp15.h | 167 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/cpu.c | 91 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/cpu_gcc.S | 82 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/entry_point.S | 111 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/interrupt.c | 183 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/interrupt.h | 29 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/mmu.c | 186 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/mmu.h | 60 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/stack.c | 90 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/startup_gcc.S | 13 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/trap.c | 225 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/vector_gcc.S | 61 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a53/cp15.h | 168 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a53/cpu.c | 91 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a53/interrupt.c | 186 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a53/interrupt.h | 18 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a53/mmu.c | 188 |
21 files changed, 2355 insertions, 0 deletions
diff --git a/libcpu/aarch64/SConscript b/libcpu/aarch64/SConscript new file mode 100644 index 0000000000..453afe4b3e --- /dev/null +++ b/libcpu/aarch64/SConscript @@ -0,0 +1,16 @@ +# RT-Thread building script for bridge + +import os +from building import * + +Import('rtconfig') + +cwd = GetCurrentDir() +group = [] +list = os.listdir(cwd) + +# cpu porting code files +if rtconfig.CPU != 'common': + group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript')) + +Return('group') diff --git a/libcpu/aarch64/cortex-a53/SConscript b/libcpu/aarch64/cortex-a53/SConscript new file mode 100644 index 0000000000..57a5accc5c --- /dev/null +++ b/libcpu/aarch64/cortex-a53/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +asm_src = Split(''' +context_gcc.S +vector_gcc.S +entry_point.S +cpu_gcc.S +''') +CPPPATH = [cwd] + +group = DefineGroup('cpu', src + asm_src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/aarch64/cortex-a53/armv8.h b/libcpu/aarch64/cortex-a53/armv8.h new file mode 100644 index 0000000000..4350890544 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/armv8.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + */ + +#ifndef __ARMV8_H__ +#define __ARMV8_H__ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long long pc; + unsigned long long spsr; + unsigned long long x30; + unsigned long long xz; + unsigned long long x28; + unsigned long long x29; + unsigned long long x26; + unsigned long long x27; + unsigned long long x24; + unsigned long long x25; + unsigned long long x22; + unsigned long long x23; + unsigned long long x20; + unsigned long long x21; + unsigned long long x18; + unsigned long long x19; + unsigned long long x16; + unsigned long long x17; + unsigned long long x14; + unsigned long long x15; + unsigned long long x12; + unsigned long long x13; + unsigned long long x10; + unsigned long long x11; + unsigned long long x8; + unsigned long long x9; + unsigned long long x6; + unsigned long long x7; + unsigned long long x4; + unsigned long long x5; + unsigned long long x2; + unsigned long long x3; + unsigned long long x0; + unsigned long long x1; +}; + +#define SP_ELx ( ( unsigned long long ) 0x01 ) +#define SP_EL0 ( ( unsigned long long ) 0x00 ) +#define PSTATE_EL1 ( ( unsigned long long ) 0x04 ) +#define PSTATE_EL2 ( ( unsigned long long ) 0x08 ) +#define PSTATE_EL3 ( ( unsigned long long ) 0x0c ) + +rt_ubase_t rt_hw_get_current_el(void); +void rt_hw_set_elx_env(void); +void rt_hw_set_current_vbar(rt_ubase_t addr); + +#endif diff --git a/libcpu/aarch64/cortex-a53/context_gcc.S b/libcpu/aarch64/cortex-a53/context_gcc.S new file mode 100644 index 0000000000..f58ea1b15d --- /dev/null +++ b/libcpu/aarch64/cortex-a53/context_gcc.S @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-10-06 ZhaoXiaowei the first version + */ + +.macro SAVE_CONTEXT + + /* Switch to use the EL0 stack pointer. */ + MSR SPSEL, #0 + + /* Save the entire context. */ + STP X0, X1, [SP, #-0x10]! + STP X2, X3, [SP, #-0x10]! + STP X4, X5, [SP, #-0x10]! + STP X6, X7, [SP, #-0x10]! + STP X8, X9, [SP, #-0x10]! + STP X10, X11, [SP, #-0x10]! + STP X12, X13, [SP, #-0x10]! + STP X14, X15, [SP, #-0x10]! + STP X16, X17, [SP, #-0x10]! + STP X18, X19, [SP, #-0x10]! + STP X20, X21, [SP, #-0x10]! + STP X22, X23, [SP, #-0x10]! + STP X24, X25, [SP, #-0x10]! + STP X26, X27, [SP, #-0x10]! + STP X28, X29, [SP, #-0x10]! + STP X30, XZR, [SP, #-0x10]! + + MRS X0, CurrentEL + CMP X0, 0xc + B.EQ 3f + CMP X0, 0x8 + B.EQ 2f + CMP X0, 0x4 + B.EQ 1f + B . +3: + MRS X3, SPSR_EL3 + /* Save the ELR. */ + MRS X2, ELR_EL3 + B 0f +2: + MRS X3, SPSR_EL2 + /* Save the ELR. */ + MRS X2, ELR_EL2 + B 0f +1: + MRS X3, SPSR_EL1 + MRS X2, ELR_EL1 + B 0f +0: + + STP X2, X3, [SP, #-0x10]! + + MOV X0, SP /* Move SP into X0 for saving. */ + + /* Switch to use the ELx stack pointer. */ + MSR SPSEL, #1 + + .endm + +.macro SAVE_CONTEXT_T + + /* Switch to use the EL0 stack pointer. */ + MSR SPSEL, #0 + + /* Save the entire context. */ + STP X0, X1, [SP, #-0x10]! + STP X2, X3, [SP, #-0x10]! + STP X4, X5, [SP, #-0x10]! + STP X6, X7, [SP, #-0x10]! + STP X8, X9, [SP, #-0x10]! + STP X10, X11, [SP, #-0x10]! + STP X12, X13, [SP, #-0x10]! + STP X14, X15, [SP, #-0x10]! + STP X16, X17, [SP, #-0x10]! + STP X18, X19, [SP, #-0x10]! + STP X20, X21, [SP, #-0x10]! + STP X22, X23, [SP, #-0x10]! + STP X24, X25, [SP, #-0x10]! + STP X26, X27, [SP, #-0x10]! + STP X28, X29, [SP, #-0x10]! + STP X30, XZR, [SP, #-0x10]! + + MRS X0, CurrentEL + CMP X0, 0xc + B.EQ 3f + CMP X0, 0x8 + B.EQ 2f + CMP X0, 0x4 + B.EQ 1f + B . +3: + MRS X3, SPSR_EL3 + MOV X2, X30 + B 0f +2: + MRS X3, SPSR_EL2 + MOV X2, X30 + B 0f +1: + MRS X3, SPSR_EL1 + MOV X2, X30 + B 0f +0: + + STP X2, X3, [SP, #-0x10]! + + MOV X0, SP /* Move SP into X0 for saving. */ + + /* Switch to use the ELx stack pointer. */ + MSR SPSEL, #1 + + .endm + +.macro RESTORE_CONTEXT + + /* Switch to use the EL0 stack pointer. */ + MSR SPSEL, #0 + + /* Set the SP to point to the stack of the task being restored. */ + MOV SP, X0 + + LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */ + + MRS X0, CurrentEL + CMP X0, 0xc + B.EQ 3f + CMP X0, 0x8 + B.EQ 2f + CMP X0, 0x4 + B.EQ 1f + B . +3: + MSR SPSR_EL3, X3 + MSR ELR_EL3, X2 + B 0f +2: + MSR SPSR_EL2, X3 + MSR ELR_EL2, X2 + B 0f +1: + MSR SPSR_EL1, X3 + MSR ELR_EL1, X2 + B 0f +0: + + LDP X30, XZR, [SP], #0x10 + LDP X28, X29, [SP], #0x10 + LDP X26, X27, [SP], #0x10 + LDP X24, X25, [SP], #0x10 + LDP X22, X23, [SP], #0x10 + LDP X20, X21, [SP], #0x10 + LDP X18, X19, [SP], #0x10 + LDP X16, X17, [SP], #0x10 + LDP X14, X15, [SP], #0x10 + LDP X12, X13, [SP], #0x10 + LDP X10, X11, [SP], #0x10 + LDP X8, X9, [SP], #0x10 + LDP X6, X7, [SP], #0x10 + LDP X4, X5, [SP], #0x10 + LDP X2, X3, [SP], #0x10 + LDP X0, X1, [SP], #0x10 + + /* Switch to use the ELx stack pointer. _RB_ Might not be required. */ + MSR SPSEL, #1 + + ERET + + .endm + +.text +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS X0, DAIF + MSR DAIFSet, #3 + DSB SY + RET + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + DSB SY + MOV X1, #0xC0 + ANDS X0, X0, X1 + B.NE rt_hw_interrupt_enable_exit + MSR DAIFClr, #3 +rt_hw_interrupt_enable_exit: + RET + +/* + * void rt_hw_context_switch_to(rt_ubase_t to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR X0, [X0] + RESTORE_CONTEXT + +.text +/* + * void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + + MOV X8,X0 + MOV X9,X1 + + SAVE_CONTEXT_T + + STR X0, [X8] // store sp in preempted tasks TCB + LDR X0, [X9] // get new task stack pointer + + RESTORE_CONTEXT + +/* + * void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ADR X2, rt_thread_switch_interrupt_flag + LDR X3, [X2] + CMP X3, #1 + B.EQ _reswitch + ADR X4, rt_interrupt_from_thread // set rt_interrupt_from_thread + MOV X3, #1 // set rt_thread_switch_interrupt_flag to 1 + STR X0, [X4] + STR X3, [X2] +_reswitch: + ADR X2, rt_interrupt_to_thread // set rt_interrupt_to_thread + STR X1, [X2] + RET + +.text + +// -- Exception handlers ---------------------------------- + + .align 8 +.globl vector_fiq +vector_fiq: + SAVE_CONTEXT + STP X0, X1, [SP, #-0x10]! + BL rt_hw_trap_fiq + LDP X0, X1, [SP], #0x10 + RESTORE_CONTEXT + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + + +// ------------------------------------------------------------------- + + .align 8 +.globl vector_irq +vector_irq: + SAVE_CONTEXT + STP X0, X1, [SP, #-0x10]! + + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + LDP X0, X1, [SP], #0x10 + + // if rt_thread_switch_interrupt_flag set, jump to + // rt_hw_context_switch_interrupt_do and don't return + ADR X1, rt_thread_switch_interrupt_flag + LDR X2, [X1] + CMP X2, #1 + B.NE vector_irq_exit + + MOV X2, #0 // clear flag + STR X2, [X1] + + ADR X3, rt_interrupt_from_thread + LDR X4, [X3] + STR x0, [X4] // store sp in preempted tasks's TCB + + ADR x3, rt_interrupt_to_thread + LDR X4, [X3] + LDR x0, [X4] // get new task's stack pointer + +vector_irq_exit: + RESTORE_CONTEXT + +// ------------------------------------------------- + + .align 8 + .globl vector_error +vector_error: + SAVE_CONTEXT + BL rt_hw_trap_error + B . diff --git a/libcpu/aarch64/cortex-a53/cp15.h b/libcpu/aarch64/cortex-a53/cp15.h new file mode 100644 index 0000000000..91c37d679f --- /dev/null +++ b/libcpu/aarch64/cortex-a53/cp15.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + */ + +#ifndef __CP15_H__ +#define __CP15_H__ + +#include "bcm283x.h" +#ifndef __STATIC_FORCEINLINE +#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif + +#define __WFI() __asm__ volatile ("wfi":::"memory") + +#define __WFE() __asm__ volatile ("wfe":::"memory") + +#define __SEV() __asm__ volatile ("sev") + +__STATIC_FORCEINLINE void __ISB(void) +{ + __asm__ volatile ("isb 0xF":::"memory"); +} + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __asm__ volatile ("dsb 0xF":::"memory"); +} + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ + +__STATIC_FORCEINLINE void __DMB(void) +{ + __asm__ volatile ("dmb 0xF":::"memory"); +} + +#ifdef RT_USING_SMP +static inline void send_ipi_msg(int cpu, int ipi_vector) +{ + IPI_MAILBOX_SET(cpu) = 1 << ipi_vector; +} + +static inline void setup_bootstrap_addr(int cpu, int addr) +{ + CORE_MAILBOX3_SET(cpu) = addr; +} + +static inline void enable_cpu_ipi_intr(int cpu) +{ + COREMB_INTCTL(cpu) = IPI_MAILBOX_INT_MASK; +} + +static inline void enable_cpu_timer_intr(int cpu) +{ + CORETIMER_INTCTL(cpu) = 0x8; +} + +static inline void enable_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL +} + +static inline void disable_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 0; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL +} + +static inline void mask_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 2; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL +} + +static inline void unmask_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl) ); // write CNTV_CTL +} + +static inline rt_uint64_t read_cntvct(void) +{ + rt_uint32_t val,val1; + asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (val),"=r" (val1)); + return (val); +} + +static inline rt_uint64_t read_cntvoff(void) +{ + + rt_uint64_t val; + asm volatile("mrrc p15, 4, %Q0, %R0, c14" : "=r" (val)); + return (val); +} + +static inline rt_uint32_t read_cntv_tval(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) ); + return val; +} + + +static inline void write_cntv_tval(rt_uint32_t val) +{ + asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) ); + return; +} + +static inline rt_uint32_t read_cntfrq(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) ); + return val; +} + + +static inline rt_uint32_t read_cntctrl(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c1, 0" : "=r"(val) ); + return val; +} + +static inline uint32_t write_cntctrl(uint32_t val) +{ + + asm volatile ("mcr p15, 0, %0, c14, c1, 0" : :"r"(val) ); + return val; +} +#endif + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_dcache_clean_flush(void); +void rt_cpu_icache_flush(void); + +void rt_cpu_vector_set_base(rt_ubase_t addr); +void rt_hw_mmu_init(void); +void rt_hw_vector_init(void); + +void set_timer_counter(unsigned int counter); +void set_timer_control(unsigned int control); +#endif diff --git a/libcpu/aarch64/cortex-a53/cpu.c b/libcpu/aarch64/cortex-a53/cpu.c new file mode 100644 index 0000000000..962a53a071 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/cpu.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + * 2019-07-28 zdzn add smp support + */ + +#include <rthw.h> +#include <rtthread.h> +#include <board.h> +#include "cp15.h" + +int rt_hw_cpu_id(void) +{ + int cpu_id; + rt_base_t value; + + __asm__ volatile ( + "mrs %0, mpidr_el1" + :"=r"(value) + ); + cpu_id = value & 0xf; + return cpu_id; +}; + +#ifdef RT_USING_SMP +void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock) +{ + lock->slock = 0; +} + +void rt_hw_spin_lock(rt_hw_spinlock_t *lock) +{ + unsigned long tmp; + unsigned long newval; + rt_hw_spinlock_t lockval; + __asm__ __volatile__( + "pld [%0]" + ::"r"(&lock->slock) + ); + + __asm__ __volatile__( + "1: ldrex %0, [%3]\n" + " add %1, %0, %4\n" + " strex %2, %1, [%3]\n" + " teq %2, #0\n" + " bne 1b" + : "=&r" (lockval), "=&r" (newval), "=&r" (tmp) + : "r" (&lock->slock), "I" (1 << 16) + : "cc"); + + while (lockval.tickets.next != lockval.tickets.owner) { + __WFE(); + lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner); + } + + __DMB(); +} + +void rt_hw_spin_unlock(rt_hw_spinlock_t *lock) +{ + __DMB(); + lock->tickets.owner++; + __DSB(); + __SEV(); +} +#endif /*RT_USING_SMP*/ + +/** + * @addtogroup ARM CPU + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/libcpu/aarch64/cortex-a53/cpu_gcc.S b/libcpu/aarch64/cortex-a53/cpu_gcc.S new file mode 100644 index 0000000000..b8c8b8768c --- /dev/null +++ b/libcpu/aarch64/cortex-a53/cpu_gcc.S @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2018-10-06 ZhaoXiaowei the first version + */ + +.text +.globl rt_hw_get_current_el +rt_hw_get_current_el: + MRS X0, CurrentEL + CMP X0, 0xc + B.EQ 3f + CMP X0, 0x8 + B.EQ 2f + CMP X0, 0x4 + B.EQ 1f + + LDR X0, =0 + B 0f +3: + LDR X0, =3 + B 0f +2: + LDR X0, =2 + B 0f +1: + LDR X0, =1 + B 0f +0: + RET + + +.globl rt_hw_set_current_vbar +rt_hw_set_current_vbar: + MRS X1, CurrentEL + CMP X1, 0xc + B.EQ 3f + CMP X1, 0x8 + B.EQ 2f + CMP X1, 0x4 + B.EQ 1f + B 0f +3: + MSR VBAR_EL3,X0 + B 0f +2: + MSR VBAR_EL2,X0 + B 0f +1: + MSR VBAR_EL1,X0 + B 0f +0: + RET + + +.globl rt_hw_set_elx_env +rt_hw_set_elx_env: + MRS X1, CurrentEL + CMP X1, 0xc + B.EQ 3f + CMP X1, 0x8 + B.EQ 2f + CMP X1, 0x4 + B.EQ 1f + B 0f +3: + MRS X0, SCR_EL3 + ORR X0, X0, #0xF /* SCR_EL3.NS|IRQ|FIQ|EA */ + MSR SCR_EL3, X0 + B 0f +2: + MRS X0, HCR_EL2 + ORR X0, X0, #0x38 + MSR HCR_EL2, X0 + B 0f +1: + B 0f +0: + RET diff --git a/libcpu/aarch64/cortex-a53/entry_point.S b/libcpu/aarch64/cortex-a53/entry_point.S new file mode 100644 index 0000000000..6d2c69226b --- /dev/null +++ b/libcpu/aarch64/cortex-a53/entry_point.S @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2020-01-15 bigmagic the first version + */ + +.section ".text.entrypoint" + +.set EL1_stack, __el1_stack + +.global _start + +// This symbol is set to 0x80000 in ld script. That is the address that raspi3's firmware +// loads 'kernel8.img' file in. +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 // MPIDR_EL1: Multi-Processor Affinity Register + and x1, x1, #3 + cbz x1, .L__cpu_0 // .L prefix is the local label in ELF + + // cpu id > 0, stop + // cpu id == 0 will also goto here after returned from entry() if possible +.L__current_cpu_idle: + wfe + b .L__current_cpu_idle + +.L__cpu_0: // cpu id == 0 + + // set stack before our code + + /* Define stack pointer for current exception level */ + // ldr x2, =EL1_stack + // mov sp, x2 + + ldr x1, =_start + + // set up EL1 + mrs x0, CurrentEL // CurrentEL Register. bit 2, 3. Others reserved + and x0, x0, #12 // clear reserved bits + + // running at EL3? + cmp x0, #12 // 1100b. So, EL3 + bne .L__not_in_el3 // 11? !EL3 -> 5: + + // should never be executed, just for completeness. (EL3) + mov x2, #0x5b1 + msr scr_el3, x2 // SCR_ELn Secure Configuration Register + mov x2, #0x3c9 + msr spsr_el3, x2 // SPSR_ELn. Saved Program Status Register. 1111001001 + adr x2, .L__not_in_el3 + msr elr_el3, x2 + eret // Exception Return: from EL3, continue from .L__not_in_el3 + + // running at EL2 or EL1 +.L__not_in_el3: + cmp x0, #4 // 0x04 0100 EL1 + beq .L__in_el1 // EL1 -> 5: + + // in EL2 + msr sp_el1, x1 // Set sp of EL1 to _start + + // enable CNTP for EL1 + mrs x0, cnthctl_el2 // Counter-timer Hypervisor Control register + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + + // enable AArch64 in EL1 + mov x0, #(1 << 31) // AArch64 + orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 + msr hcr_el2, x0 + mrs x0, hcr_el2 + + // change execution level to EL1 + mov x2, #0x3c4 + msr spsr_el2, x2 // 1111000100 + adr x2, .L__in_el1 + msr elr_el2, x2 + eret // exception return. from EL2. continue from .L__in_el1 + +.L__in_el1: + mov sp, x1 // in EL1. Set sp to _start + + // Set CPACR_EL1 (Architecture Feature Access Control Register) to avoid trap from SIMD or float point instruction + mov x1, #0x00300000 // Don't trap any SIMD/FP instructions in both EL0 and EL1 + msr cpacr_el1, x1 + + mrs x1, sctlr_el1 + orr x1, x1, #(1 << 12) + bic x1, x1, #(3 << 3) + bic x1, x1, #(1 << 1) + msr sctlr_el1, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +.L__clean_bss_loop: + cbz w2, .L__jump_to_entry + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, .L__clean_bss_loop + + // jump to C code, should not return +.L__jump_to_entry: + bl entry + // for failsafe, halt this core too + b .L__current_cpu_idle diff --git a/libcpu/aarch64/cortex-a53/interrupt.c b/libcpu/aarch64/cortex-a53/interrupt.c new file mode 100644 index 0000000000..8ad60c6de2 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/interrupt.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018/5/3 Bernard first version + * 2019-07-28 zdzn add smp support + * 2019-08-09 zhangjun fixup the problem of smp startup and scheduling issues, + * write addr to mailbox3 to startup smp, and we use mailbox0 for ipi + */ + +#include <rthw.h> +#include <rtthread.h> + +#include "cp15.h" +#include "armv8.h" + +#include <board.h> + +#define MAX_HANDLERS 72 + +#ifdef RT_USING_SMP +#define rt_interrupt_nest rt_cpu_self()->irq_nest +#else +extern volatile rt_uint8_t rt_interrupt_nest; +#endif + +extern int system_vectors; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +rt_ubase_t rt_interrupt_from_thread; +rt_ubase_t rt_interrupt_to_thread; +rt_ubase_t rt_thread_switch_interrupt_flag; + +void rt_hw_vector_init(void) +{ + rt_hw_set_current_vbar((rt_ubase_t)&system_vectors); // cpu_gcc.S +} + +static void default_isr_handler(int vector, void *param) +{ +#ifdef RT_USING_SMP + rt_kprintf("cpu %d unhandled irq: %d\n", rt_hw_cpu_id(),vector); +#else + rt_kprintf("unhandled irq: %d\n",vector); +#endif +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_uint32_t index; + + /* mask all of interrupts */ + IRQ_DISABLE_BASIC = 0x000000ff; + IRQ_DISABLE1 = 0xffffffff; + IRQ_DISABLE2 = 0xffffffff; + for (index = 0; index < MAX_HANDLERS; index ++) + { + isr_table[index].handler = default_isr_handler; + isr_table[index].param = NULL; +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[index].name, "unknown", RT_NAME_MAX); + isr_table[index].counter = 0; +#endif + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + if (vector < 32) + { + IRQ_DISABLE1 = (1 << vector); + } + else if (vector<64) + { + vector = vector % 32; + IRQ_DISABLE2 = (1 << vector); + } + else + { + vector = vector - 64; + IRQ_DISABLE_BASIC = (1 << vector); + } +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + if (vector < 32) + { + IRQ_ENABLE1 = (1 << vector); + } + else if (vector < 64) + { + vector = vector % 32; + IRQ_ENABLE2 = (1 << vector); + } + else + { + vector = vector - 64; + IRQ_ENABLE_BASIC = (1 << vector); + } +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +#ifdef RT_USING_SMP +void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask) +{ + __DSB(); + if(cpu_mask & 0x1) + { + send_ipi_msg(0, ipi_vector); + } + if(cpu_mask & 0x2) + { + send_ipi_msg(1, ipi_vector); + } + if(cpu_mask & 0x4) + { + send_ipi_msg(2, ipi_vector); + } + if(cpu_mask & 0x8) + { + send_ipi_msg(3, ipi_vector); + } + __DSB(); +} +#endif + +#ifdef RT_USING_SMP +void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler) +{ + /* note: ipi_vector maybe different with irq_vector */ + rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER"); +} +#endif diff --git a/libcpu/aarch64/cortex-a53/interrupt.h b/libcpu/aarch64/cortex-a53/interrupt.h new file mode 100644 index 0000000000..0c20f79bcc --- /dev/null +++ b/libcpu/aarch64/cortex-a53/interrupt.h @@ -0,0 +1,29 @@ + +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#include <rthw.h> +#include <board.h> + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +//void rt_hw_vector_init(void); + +void rt_hw_interrupt_init(void); +void rt_hw_interrupt_mask(int vector); +void rt_hw_interrupt_umask(int vector); + +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name); + +#endif diff --git a/libcpu/aarch64/cortex-a53/mmu.c b/libcpu/aarch64/cortex-a53/mmu.c new file mode 100644 index 0000000000..29934b26a4 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/mmu.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-01-10 bernard porting to AM1808 + * 2019-07-28 zdzn add smp support + */ + +#include "mmu.h" + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* 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, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ +#if 0 + 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; +#else + return 0; +#endif +} + +void rt_hw_init_mmu_table() +{ + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0x00000000, 0x3effffff, 0x00000000, NORMAL_MEM); + /* IO memory region */ + rt_hw_mmu_setmtt(0x3f000000, 0x40010000, 0x3f000000, DEVICE_MEM); +} + +void rt_hw_change_mmu_table(rt_uint32_t vaddrStart, + rt_uint32_t size, + rt_uint32_t paddrStart, rt_uint32_t attr) +{ + rt_hw_mmu_setmtt(vaddrStart, vaddrStart+size-1, paddrStart, attr); +} + +void rt_hw_mmu_init(void) +{ + rt_cpu_dcache_clean_flush(); + rt_cpu_icache_flush(); + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} diff --git a/libcpu/aarch64/cortex-a53/mmu.h b/libcpu/aarch64/cortex-a53/mmu.h new file mode 100644 index 0000000000..5bef609486 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/mmu.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-01-15 bigmagic the first version + */ +#ifndef MMU_H__ +#define MMU_H__ +#include <rtthread.h> +#include <rthw.h> +#include <board.h> +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) // eXecute Never +#define SHARED (1<<16) /* shareable */ +#define SHAREDEVICE (1<<2) /* shared device */ +#define STRONGORDER (0<<2) /* strong ordered */ +#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */ + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write without cache and write buffer */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +/* device mapping type */ +#define DEVICE_MEM (SHARED|SHAREDEVICE|RW_NCNBXN) +/* normal memory mapping type */ +#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC) +#define STRONG_ORDER_MEM (SHARED|AP_RO|XN|DESC_SEC) +#define BUS_ADDRESS(phys) (((phys) & ~0xC0000000) | 0xC0000000) + +void rt_hw_change_mmu_table(rt_uint32_t vaddrStart, + rt_uint32_t size, + rt_uint32_t paddrStart, rt_uint32_t attr); +#endif diff --git a/libcpu/aarch64/cortex-a53/stack.c b/libcpu/aarch64/cortex-a53/stack.c new file mode 100644 index 0000000000..68222c2c67 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/stack.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include <rtthread.h> +#include <board.h> + +#include <armv8.h> + +#define INITIAL_SPSR_EL3 (PSTATE_EL3 | SP_EL0) +#define INITIAL_SPSR_EL2 (PSTATE_EL2 | SP_EL0) +#define INITIAL_SPSR_EL1 (PSTATE_EL1 | SP_EL0) + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_ubase_t *stk; + rt_ubase_t current_el; + + stk = (rt_ubase_t*)stack_addr; + + *(--stk) = ( rt_ubase_t ) 11; /* X1 */ + *(--stk) = ( rt_ubase_t ) parameter; /* X0 */ + *(--stk) = ( rt_ubase_t ) 33; /* X3 */ + *(--stk) = ( rt_ubase_t ) 22; /* X2 */ + *(--stk) = ( rt_ubase_t ) 55; /* X5 */ + *(--stk) = ( rt_ubase_t ) 44; /* X4 */ + *(--stk) = ( rt_ubase_t ) 77; /* X7 */ + *(--stk) = ( rt_ubase_t ) 66; /* X6 */ + *(--stk) = ( rt_ubase_t ) 99; /* X9 */ + *(--stk) = ( rt_ubase_t ) 88; /* X8 */ + *(--stk) = ( rt_ubase_t ) 11; /* X11 */ + *(--stk) = ( rt_ubase_t ) 10; /* X10 */ + *(--stk) = ( rt_ubase_t ) 13; /* X13 */ + *(--stk) = ( rt_ubase_t ) 12; /* X12 */ + *(--stk) = ( rt_ubase_t ) 15; /* X15 */ + *(--stk) = ( rt_ubase_t ) 14; /* X14 */ + *(--stk) = ( rt_ubase_t ) 17; /* X17 */ + *(--stk) = ( rt_ubase_t ) 16; /* X16 */ + *(--stk) = ( rt_ubase_t ) 19; /* X19 */ + *(--stk) = ( rt_ubase_t ) 18; /* X18 */ + *(--stk) = ( rt_ubase_t ) 21; /* X21 */ + *(--stk) = ( rt_ubase_t ) 20; /* X20 */ + *(--stk) = ( rt_ubase_t ) 23; /* X23 */ + *(--stk) = ( rt_ubase_t ) 22; /* X22 */ + *(--stk) = ( rt_ubase_t ) 25; /* X25 */ + *(--stk) = ( rt_ubase_t ) 24; /* X24 */ + *(--stk) = ( rt_ubase_t ) 27; /* X27 */ + *(--stk) = ( rt_ubase_t ) 26; /* X26 */ + *(--stk) = ( rt_ubase_t ) 29; /* X29 */ + *(--stk) = ( rt_ubase_t ) 28; /* X28 */ + *(--stk) = ( rt_ubase_t ) 0; /* XZR - has no effect, used so there are an even number of registers. */ + *(--stk) = ( rt_ubase_t ) texit; /* X30 - procedure call link register. */ + + current_el = rt_hw_get_current_el(); + + if(current_el == 3) + { + *(--stk) = INITIAL_SPSR_EL3; + } + else if(current_el == 2) + { + *(--stk) = INITIAL_SPSR_EL2; + } + else + { + *(--stk) = INITIAL_SPSR_EL1; + } + + *(--stk) = ( rt_ubase_t ) tentry; /* Exception return address. */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} diff --git a/libcpu/aarch64/cortex-a53/startup_gcc.S b/libcpu/aarch64/cortex-a53/startup_gcc.S new file mode 100644 index 0000000000..ea4268148c --- /dev/null +++ b/libcpu/aarch64/cortex-a53/startup_gcc.S @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + + .global Reset_Handler + .section ".start", "ax" +Reset_Handler: + nop diff --git a/libcpu/aarch64/cortex-a53/trap.c b/libcpu/aarch64/cortex-a53/trap.c new file mode 100644 index 0000000000..13ae6d1b9e --- /dev/null +++ b/libcpu/aarch64/cortex-a53/trap.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2018-10-06 ZhaoXiaowei the first version + */ + +#include <rtthread.h> +#include <rthw.h> + +#include "interrupt.h" +#include "armv8.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%16.16llx r01:0x%16.16llx r02:0x%16.16llx r03:0x%16.16llx\n", regs->x0, regs->x1, regs->x2, regs->x3); + rt_kprintf("r04:0x%16.16llx r05:0x%16.16llx r06:0x%16.16llx r07:0x%16.16llx\n", regs->x4, regs->x5, regs->x6, regs->x7); + rt_kprintf("r08:0x%16.16llx r09:0x%16.16llx r10:0x%16.16llx r11:0x%16.16llx\n", regs->x8, regs->x9, regs->x10, regs->x11); + rt_kprintf("r12:0x%16.16llx r13:0x%16.16llx r14:0x%16.16llx r15:0x%16.16llx\n", regs->x12, regs->x13, regs->x14, regs->x15); + rt_kprintf("r16:0x%16.16llx r17:0x%16.16llx r18:0x%16.16llx r19:0x%16.16llx\n", regs->x16, regs->x17, regs->x18, regs->x19); + rt_kprintf("r20:0x%16.16llx r21:0x%16.16llx r22:0x%16.16llx r23:0x%16.16llx\n", regs->x20, regs->x21, regs->x22, regs->x23); + rt_kprintf("r24:0x%16.16llx r25:0x%16.16llx r26:0x%16.16llx r27:0x%16.16llx\n", regs->x24, regs->x25, regs->x26, regs->x27); + rt_kprintf("r28:0x%16.16llx r29:0x%16.16llx r30:0x%16.16llx", regs->x28, regs->x29, regs->x30); + rt_kprintf("spsr:0x%16.16llx", regs->spsr); + rt_kprintf("return pc:0x%16.16llx", regs->pc); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_error(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("error exception:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +#define GIC_ACK_INTID_MASK 0x000003ff + +void rt_hw_trap_irq(void) +{ + void *param; + uint32_t irq; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + uint32_t value = 0; + value = IRQ_PEND_BASIC & 0x3ff; +#ifdef RT_USING_SMP + uint32_t mailbox_data; + uint32_t cpu_id = rt_hw_cpu_id(); + uint32_t int_source = CORE_IRQSOURCE(cpu_id); + mailbox_data = IPI_MAILBOX_CLEAR(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); + } + } + } + if (int_source & 0xf0) + { + /*it's a ipi interrupt*/ + if (mailbox_data & 0x1){ + /* clear mailbox */ + IPI_MAILBOX_CLEAR(cpu_id) = mailbox_data; + isr_func = isr_table[IRQ_ARM_MAILBOX].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[IRQ_ARM_MAILBOX].counter++; +#endif + if (isr_func) + { + param = isr_table[IRQ_ARM_MAILBOX].param; + isr_func(IRQ_ARM_MAILBOX, param); + } + } + else + CORE_MAILBOX3_CLEAR(cpu_id) = mailbox_data; + } +#endif + /* 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); + } + } +} + +void rt_hw_trap_fiq(void) +{ + void *param; + uint32_t irq; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + uint32_t value = 0; + value = IRQ_PEND_BASIC & 0x3ff; +#ifdef RT_USING_SMP + uint32_t mailbox_data; + uint32_t cpu_id = rt_hw_cpu_id(); + uint32_t int_source = CORE_IRQSOURCE(cpu_id); + mailbox_data = IPI_MAILBOX_CLEAR(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); + } + } + } + if (int_source & 0xf0) + { + /*it's a ipi interrupt*/ + if (mailbox_data & 0x1) + { + /* clear mailbox */ + IPI_MAILBOX_CLEAR(cpu_id) = mailbox_data; + isr_func = isr_table[IRQ_ARM_MAILBOX].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[IRQ_ARM_MAILBOX].counter++; +#endif + if (isr_func) + { + param = isr_table[IRQ_ARM_MAILBOX].param; + isr_func(IRQ_ARM_MAILBOX, param); + } + } + else + CORE_MAILBOX3_CLEAR(cpu_id) = mailbox_data; + } +#endif + /* 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 (irq > 1) + rt_kprintf("interrupt fiq %d\n", irq); + if (isr_func) + { + /* Interrupt for myself. */ + param = isr_table[irq].param; + /* turn to interrupt service routine */ + isr_func(irq, param); + } + } +} diff --git a/libcpu/aarch64/cortex-a53/vector_gcc.S b/libcpu/aarch64/cortex-a53/vector_gcc.S new file mode 100644 index 0000000000..fc88cce7f8 --- /dev/null +++ b/libcpu/aarch64/cortex-a53/vector_gcc.S @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006-2020, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2018-10-06 ZhaoXiaowei the first version + */ + +.text + +.globl system_vectors +.globl vector_error +.globl vector_irq +.globl vector_fiq + +system_vectors: +.align 11 + .set VBAR, system_vectors + .org VBAR + // Exception from CurrentEL (EL1) with SP_EL0 (SPSEL=1) + .org (VBAR + 0x00 + 0) + B vector_error // Synchronous + .org (VBAR + 0x80 + 0) + B vector_irq // IRQ/vIRQ + .org (VBAR + 0x100 + 0) + B vector_fiq // FIQ/vFIQ + .org (VBAR + 0x180 + 0) + B vector_error // Error/vError + + // Exception from CurrentEL (EL1) with SP_ELn + .org (VBAR + 0x200 + 0) + B vector_error // Synchronous + .org (VBAR + 0x280 + 0) + B vector_irq // IRQ/vIRQ + .org (VBAR + 0x300 + 0) + B vector_fiq // FIQ/vFIQ + .org (VBAR + 0x380 + 0) + B vector_error + + // Exception from lower EL, aarch64 + .org (VBAR + 0x400 + 0) + B vector_error + .org (VBAR + 0x480 + 0) + B vector_error + .org (VBAR + 0x500 + 0) + B vector_error + .org (VBAR + 0x580 + 0) + B vector_error + + // Exception from lower EL, aarch32 + .org (VBAR + 0x600 + 0) + B vector_error + .org (VBAR + 0x680 + 0) + B vector_error + .org (VBAR + 0x700 + 0) + B vector_error + .org (VBAR + 0x780 + 0) + B vector_error + .org (VBAR + 0x800 + 0) + B vector_error diff --git a/libcpu/arm/cortex-a53/cp15.h b/libcpu/arm/cortex-a53/cp15.h new file mode 100644 index 0000000000..14b85b7e64 --- /dev/null +++ b/libcpu/arm/cortex-a53/cp15.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + */ +#include "raspi.h" +#ifndef __CP15_H__ +#define __CP15_H__ + +#ifndef __STATIC_FORCEINLINE +#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline +#endif + +#define __WFI() __asm__ volatile ("wfi":::"memory") + +#define __WFE() __asm__ volatile ("wfe":::"memory") + +#define __SEV() __asm__ volatile ("sev") + +__STATIC_FORCEINLINE void __ISB(void) +{ + __asm__ volatile ("isb 0xF":::"memory"); +} + + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__STATIC_FORCEINLINE void __DSB(void) +{ + __asm__ volatile ("dsb 0xF":::"memory"); +} + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ + +__STATIC_FORCEINLINE void __DMB(void) +{ + __asm__ volatile ("dmb 0xF":::"memory"); +} + + +#ifdef RT_USING_SMP +static inline void send_ipi_msg(int cpu, int ipi_vector) +{ + IPI_MAILBOX_SET(cpu) = 1 << ipi_vector; +} + +static inline void setup_bootstrap_addr(int cpu, int addr) +{ + CORE_MAILBOX3_SET(cpu) = addr; +} + +static inline void enable_cpu_ipi_intr(int cpu) +{ + COREMB_INTCTL(cpu) = IPI_MAILBOX_INT_MASK; +} + +static inline void enable_cpu_timer_intr(int cpu) +{ + CORETIMER_INTCTL(cpu) = 0x8; +} + +static inline void enable_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl)); // write CNTV_CTL +} + +static inline void disable_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 0; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl)); // write CNTV_CTL +} + +static inline void mask_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 2; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl)); // write CNTV_CTL +} + +static inline void unmask_cntv(void) +{ + rt_uint32_t cntv_ctl; + cntv_ctl = 1; + asm volatile ("mcr p15, 0, %0, c14, c3, 1" :: "r"(cntv_ctl)); // write CNTV_CTL +} + +static inline rt_uint64_t read_cntvct(void) +{ + rt_uint32_t val,val1; + asm volatile ("mrrc p15, 1, %0, %1, c14" : "=r" (val),"=r" (val1)); + return (val); +} + +static inline rt_uint64_t read_cntvoff(void) +{ + + rt_uint64_t val; + asm volatile ("mrrc p15, 4, %Q0, %R0, c14" : "=r" (val)); + return (val); +} + +static inline rt_uint32_t read_cntv_tval(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val)); + return val; +} + + +static inline void write_cntv_tval(rt_uint32_t val) +{ + asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val)); + return; +} + +static inline rt_uint32_t read_cntfrq(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val)); + return val; +} + + +static inline rt_uint32_t read_cntctrl(void) +{ + rt_uint32_t val; + asm volatile ("mrc p15, 0, %0, c14, c1, 0" : "=r"(val)); + return val; +} + +static inline uint32_t write_cntctrl(uint32_t val) +{ + + asm volatile ("mcr p15, 0, %0, c14, c1, 0" : :"r"(val)); + return val; +} +#endif + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_dcache_clean_flush(void); +void rt_cpu_icache_flush(void); + +void rt_cpu_vector_set_base(unsigned int addr); +void rt_hw_mmu_init(void); +void rt_hw_vector_init(void); + +void set_timer_counter(unsigned int counter); +void set_timer_control(unsigned int control); +#endif diff --git a/libcpu/arm/cortex-a53/cpu.c b/libcpu/arm/cortex-a53/cpu.c new file mode 100644 index 0000000000..4d02ca35e1 --- /dev/null +++ b/libcpu/arm/cortex-a53/cpu.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + * 2019-07-28 zdzn add smp support + */ + +#include <rthw.h> +#include <rtthread.h> +#include <board.h> +#include "cp15.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) +{ + lock->slock = 0; +} + +void rt_hw_spin_lock(rt_hw_spinlock_t *lock) +{ + unsigned long tmp; + unsigned long newval; + rt_hw_spinlock_t lockval; + __asm__ __volatile__( + "pld [%0]" + ::"r"(&lock->slock) + ); + + __asm__ __volatile__( + "1: ldrex %0, [%3]\n" + " add %1, %0, %4\n" + " strex %2, %1, [%3]\n" + " teq %2, #0\n" + " bne 1b" + : "=&r" (lockval), "=&r" (newval), "=&r" (tmp) + : "r" (&lock->slock), "I" (1 << 16) + : "cc"); + + while (lockval.tickets.next != lockval.tickets.owner) + { + __WFE(); + lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner); + } + + __DMB(); +} + +void rt_hw_spin_unlock(rt_hw_spinlock_t *lock) +{ + __DMB(); + lock->tickets.owner++; + __DSB(); + __SEV(); +} +#endif /*RT_USING_SMP*/ + +/** + * @addtogroup ARM CPU + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/libcpu/arm/cortex-a53/interrupt.c b/libcpu/arm/cortex-a53/interrupt.c new file mode 100644 index 0000000000..c9e7c17f8f --- /dev/null +++ b/libcpu/arm/cortex-a53/interrupt.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018/5/3 Bernard first version + * 2019-07-28 zdzn add smp support + * 2019-08-09 zhangjun fixup the problem of smp startup and scheduling issues, + * write addr to mailbox3 to startup smp, and we use mailbox0 for ipi + */ + +#include <rthw.h> +#include <rtthread.h> + +#include "cp15.h" +#include <board.h> + +#define MAX_HANDLERS 72 + +#ifdef RT_USING_SMP +#define rt_interrupt_nest rt_cpu_self()->irq_nest +#else +extern volatile rt_uint8_t rt_interrupt_nest; +#endif + +const unsigned int VECTOR_BASE = 0x00; +extern void rt_cpu_vector_set_base(unsigned int addr); +extern int system_vectors; + +void rt_hw_vector_init(void) +{ + rt_cpu_vector_set_base((unsigned int)&system_vectors); +} + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +rt_uint32_t rt_interrupt_from_thread; +rt_uint32_t rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +extern int system_vectors; + +static void default_isr_handler(int vector, void *param) +{ +#ifdef RT_USING_SMP + rt_kprintf("cpu %d unhandled irq: %d\n", rt_hw_cpu_id(),vector); +#else + rt_kprintf("unhandled irq: %d\n",vector); +#endif +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_uint32_t index; + + /* mask all of interrupts */ + IRQ_DISABLE_BASIC = 0x000000ff; + IRQ_DISABLE1 = 0xffffffff; + IRQ_DISABLE2 = 0xffffffff; + for (index = 0; index < MAX_HANDLERS; index ++) + { + isr_table[index].handler = default_isr_handler; + isr_table[index].param = NULL; +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[index].name, "unknown", RT_NAME_MAX); + isr_table[index].counter = 0; +#endif + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + + if (vector < 32) + { + IRQ_DISABLE1 = (1 << vector); + } + else if (vector < 64) + { + vector = vector % 32; + IRQ_DISABLE2 = (1 << vector); + } + else + { + vector = vector - 64; + IRQ_DISABLE_BASIC = (1 << vector); + } +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + if (vector < 32) + { + IRQ_ENABLE1 = (1 << vector); + } + else if (vector < 64) + { + vector = vector % 32; + IRQ_ENABLE2 = (1 << vector); + } + else + { + vector = vector - 64; + IRQ_ENABLE_BASIC = (1 << vector); + } +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +#ifdef RT_USING_SMP +void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask) +{ + __DSB(); + if (cpu_mask & 0x1) + { + send_ipi_msg(0, ipi_vector); + } + if (cpu_mask & 0x2) + { + send_ipi_msg(1, ipi_vector); + } + if (cpu_mask & 0x4) + { + send_ipi_msg(2, ipi_vector); + } + if (cpu_mask & 0x8) + { + send_ipi_msg(3, ipi_vector); + } + __DSB(); +} +#endif + +#ifdef RT_USING_SMP +void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler) +{ + /* note: ipi_vector maybe different with irq_vector */ + rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER"); +} +#endif diff --git a/libcpu/arm/cortex-a53/interrupt.h b/libcpu/arm/cortex-a53/interrupt.h new file mode 100644 index 0000000000..9aae0f556a --- /dev/null +++ b/libcpu/arm/cortex-a53/interrupt.h @@ -0,0 +1,18 @@ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#include <rthw.h> +#include <board.h> + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +void rt_hw_interrupt_init(void); +void rt_hw_interrupt_mask(int vector); +void rt_hw_interrupt_umask(int vector); + +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name); + +#endif diff --git a/libcpu/arm/cortex-a53/mmu.c b/libcpu/arm/cortex-a53/mmu.c new file mode 100644 index 0000000000..b3541d2ad4 --- /dev/null +++ b/libcpu/arm/cortex-a53/mmu.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2006-2019, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-01-10 bernard porting to AM1808 + * 2019-07-28 zdzn add smp support + */ + +#include "mmu.h" + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* 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, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for (i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +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() +{ + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0x00000000, 0x3effffff, 0x00000000, NORMAL_MEM); + /* IO memory region */ + rt_hw_mmu_setmtt(0x3f000000, 0x40010000, 0x3f000000, DEVICE_MEM); +} + +void rt_hw_change_mmu_table(rt_uint32_t vaddrStart, + rt_uint32_t size, + rt_uint32_t paddrStart, rt_uint32_t attr) +{ + rt_hw_mmu_setmtt(vaddrStart, vaddrStart+size-1, paddrStart, attr); +#ifndef RT_USING_SMP + rt_cpu_dcache_clean_flush(); + rt_cpu_icache_flush(); +#endif +} + + +void rt_hw_mmu_init(void) +{ + rt_cpu_dcache_clean_flush(); + rt_cpu_icache_flush(); + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + |
