mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-22 11:30:01 +08:00
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 <zhangbingru@rt-thread.com>
Co-authored-by: zhkag <zhkag@foxmail.com>
This commit is contained in:
+57
-1
@@ -1,16 +1,34 @@
|
||||
config ARCH_CPU_64BIT
|
||||
bool
|
||||
|
||||
config RT_USING_CACHE
|
||||
bool
|
||||
default n
|
||||
|
||||
config ARCH_CPU_BIG_ENDIAN
|
||||
bool
|
||||
|
||||
config ARCH_ARM
|
||||
config ARCH_ARM_BOOTWITH_FLUSH_CACHE
|
||||
bool
|
||||
default n
|
||||
|
||||
config ARCH_CPU_STACK_GROWS_UPWARD
|
||||
bool
|
||||
default n
|
||||
|
||||
config RT_USING_CPU_FFS
|
||||
bool
|
||||
default n
|
||||
|
||||
config ARCH_MM_MMU
|
||||
bool
|
||||
|
||||
config ARCH_MM_MPU
|
||||
bool
|
||||
|
||||
config ARCH_ARM
|
||||
bool
|
||||
|
||||
config ARCH_ARM_CORTEX_M
|
||||
bool
|
||||
select ARCH_ARM
|
||||
@@ -33,6 +51,7 @@ config ARCH_ARM_CORTEX_M3
|
||||
config ARCH_ARM_MPU
|
||||
bool
|
||||
depends on ARCH_ARM
|
||||
select ARCH_MM_MPU
|
||||
|
||||
config ARCH_ARM_CORTEX_M4
|
||||
bool
|
||||
@@ -43,6 +62,7 @@ config ARCH_ARM_CORTEX_M7
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_M
|
||||
select RT_USING_CPU_FFS
|
||||
select RT_USING_CACHE
|
||||
|
||||
config ARCH_ARM_CORTEX_M33
|
||||
bool
|
||||
@@ -55,8 +75,33 @@ config ARCH_ARM_CORTEX_R
|
||||
|
||||
config ARCH_ARM_MMU
|
||||
bool
|
||||
select RT_USING_CACHE
|
||||
select ARCH_MM_MMU
|
||||
depends on ARCH_ARM
|
||||
|
||||
config RT_USING_USERSPACE
|
||||
bool "Isolated user space"
|
||||
default n
|
||||
depends on ARCH_MM_MMU
|
||||
|
||||
config KERNEL_VADDR_START
|
||||
hex "The virtural address of kernel start"
|
||||
default 0xc0000000 if ARCH_ARM
|
||||
default 0x80000000 if ARCH_RISCV
|
||||
depends on RT_USING_USERSPACE
|
||||
|
||||
config PV_OFFSET
|
||||
hex "The offset of kernel physical address and virtural address"
|
||||
default 0xa0000000 if ARCH_ARM
|
||||
default 0x0 if ARCH_RISCV
|
||||
depends on RT_USING_USERSPACE
|
||||
|
||||
config RT_IOREMAP_LATE
|
||||
bool "Support to create IO mapping in the kernel address space after system initlalization."
|
||||
default n
|
||||
depends on ARCH_ARM_CORTEX_A
|
||||
depends on RT_USING_USERSPACE
|
||||
|
||||
config ARCH_ARM_ARM9
|
||||
bool
|
||||
select ARCH_ARM
|
||||
@@ -104,8 +149,19 @@ config ARCH_ARM_CORTEX_A9
|
||||
bool
|
||||
select ARCH_ARM_CORTEX_A
|
||||
|
||||
config ARCH_ARM_SECURE_MODE
|
||||
bool "Running in secure mode [ARM Cortex-A]"
|
||||
default n
|
||||
depends on ARCH_ARM_CORTEX_A
|
||||
|
||||
config RT_BACKTRACE_FUNCTION_NAME
|
||||
bool "To show function name when backtrace."
|
||||
default n
|
||||
depends on ARCH_ARM_CORTEX_A
|
||||
|
||||
config ARCH_ARMV8
|
||||
bool
|
||||
select ARCH_ARM
|
||||
|
||||
config ARCH_MIPS
|
||||
bool
|
||||
|
||||
@@ -20,6 +20,16 @@
|
||||
#define __DSB() __asm__ volatile ("dsb 0xf":::"memory")
|
||||
#define __DMB() __asm__ volatile ("dmb 0xf":::"memory")
|
||||
|
||||
#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");
|
||||
|
||||
@@ -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__*/
|
||||
@@ -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__*/
|
||||
@@ -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
|
||||
@@ -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]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
+40
-10
@@ -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
|
||||
|
||||
@@ -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 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]
|
||||
#ifdef RT_USING_USERSPACE
|
||||
push {r1, lr}
|
||||
mov r0, r2
|
||||
bl lwp_user_setting_save
|
||||
pop {r1, lr}
|
||||
#endif
|
||||
_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
|
||||
#else
|
||||
/* now from_thread(r2) to_thread(r3) not used */
|
||||
ldr ip, =rt_thread_switch_interrupt_flag
|
||||
ldr r3, [ip]
|
||||
cmp r3, #1
|
||||
beq _reswitch
|
||||
ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
|
||||
str r0, [r3]
|
||||
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
|
||||
str r3, [ip]
|
||||
_reswitch:
|
||||
ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
|
||||
str r1, [ip]
|
||||
bx lr
|
||||
#endif
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
.global rt_hw_context_switch_exit
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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__*/
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+662
-13
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
/*@{*/
|
||||
|
||||
|
||||
+386
-193
File diff suppressed because it is too large
Load Diff
+177
-101
@@ -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)
|
||||
#ifdef RT_USING_LWP
|
||||
if (dbg_check_event(regs, 4))
|
||||
{
|
||||
rt_kprintf("prefetch abort:\n");
|
||||
rt_hw_show_register(regs);
|
||||
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
|
||||
list_thread();
|
||||
return;
|
||||
}
|
||||
check_user_fault(regs, 4, "User prefetch abort");
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "prefetch abort", PABT_EXCEPTION);
|
||||
}
|
||||
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();
|
||||
return;
|
||||
}
|
||||
if (check_user_stack(regs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
check_user_fault(regs, 8, "User data abort");
|
||||
#endif
|
||||
rt_hw_cpu_shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_trap_hook(regs, "data abort", DABT_EXCEPTION);
|
||||
}
|
||||
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;
|
||||
|
||||
if(core_timer_flag != 0)
|
||||
{
|
||||
uint32_t cpu_id = rt_hw_cpu_id();
|
||||
uint32_t int_source = CORE_IRQSOURCE(cpu_id);
|
||||
if (int_source & 0x0f)
|
||||
{
|
||||
if (int_source & 0x08)
|
||||
{
|
||||
isr_func = isr_table[IRQ_ARM_TIMER].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[IRQ_ARM_TIMER].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
param = isr_table[IRQ_ARM_TIMER].param;
|
||||
isr_func(IRQ_ARM_TIMER, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* local interrupt*/
|
||||
if (value)
|
||||
{
|
||||
if (value & (1 << 8))
|
||||
{
|
||||
value = IRQ_PEND1;
|
||||
irq = __rt_ffs(value) - 1;
|
||||
}
|
||||
else if (value & (1 << 9))
|
||||
{
|
||||
value = IRQ_PEND2;
|
||||
irq = __rt_ffs(value) + 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
value &= 0x0f;
|
||||
irq = __rt_ffs(value) + 63;
|
||||
}
|
||||
|
||||
/* get interrupt service routine */
|
||||
isr_func = isr_table[irq].handler;
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
isr_table[irq].counter++;
|
||||
#endif
|
||||
if (isr_func)
|
||||
{
|
||||
/* Interrupt for myself. */
|
||||
param = isr_table[irq].param;
|
||||
/* turn to interrupt service routine */
|
||||
isr_func(irq, param);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void *param;
|
||||
int ir, ir_real;
|
||||
rt_isr_handler_t isr_func;
|
||||
extern struct rt_irq_desc isr_table[];
|
||||
|
||||
int_ack = rt_hw_interrupt_get_irq();
|
||||
ir = rt_hw_interrupt_get_irq();
|
||||
|
||||
ir = int_ack & GIC_ACK_INTID_MASK;
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__*/
|
||||
@@ -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__*/
|
||||
@@ -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__*/
|
||||
@@ -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__*/
|
||||
@@ -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__*/
|
||||
@@ -16,6 +16,8 @@ elif rtconfig.CPU == "nuclei" :
|
||||
group = group
|
||||
elif rtconfig.CPU == "virt64" :
|
||||
group = group
|
||||
elif rtconfig.CPU == "c906" :
|
||||
group = group
|
||||
elif rtconfig.CPU == "ch32v1" :
|
||||
group = group
|
||||
elif rtconfig.CPU == "ch32v3" :
|
||||
@@ -26,7 +28,7 @@ else :
|
||||
group = group + SConscript(os.path.join('common', 'SConscript'))
|
||||
|
||||
# cpu porting code files
|
||||
if rtconfig.CPU == "e9xx" :
|
||||
if rtconfig.CPU == "e9xx" or rtconfig.CPU == "c906":
|
||||
group = group + SConscript(os.path.join(rtconfig.VENDOR, rtconfig.CPU, 'SConscript'))
|
||||
elif rtconfig.CPU in list:
|
||||
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* 2020/11/20 BalanceTWK Add FPU support
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "cpuport.h"
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
|
||||
@@ -138,7 +138,7 @@ rt_uint8_t *rt_hw_stack_init(void *tentry,
|
||||
* #endif
|
||||
*/
|
||||
#ifndef RT_USING_SMP
|
||||
RT_WEAK void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to)
|
||||
RT_WEAK void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
|
||||
{
|
||||
if (rt_thread_switch_interrupt_flag == 0)
|
||||
rt_interrupt_from_thread = from;
|
||||
|
||||
@@ -14,6 +14,18 @@
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#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
|
||||
|
||||
/* bytes of register width */
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define STORE sd
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* 2018/12/27 Jesven Add SMP schedule
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "cpuport.h"
|
||||
|
||||
.section .text.entry
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* 2018/12/27 Jesven Add SMP support
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#define MSTATUS_FS 0x00006000U /* initial state of FPU */
|
||||
#include <cpuport.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S')
|
||||
CPPPATH = [cwd]
|
||||
ASFLAGS = ''
|
||||
|
||||
group = DefineGroup('cpu', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef _SBI_ASM_H
|
||||
#define _SBI_ASM_H
|
||||
|
||||
.macro SBI_CALL which
|
||||
li a7, \which
|
||||
ecall
|
||||
nop
|
||||
.endm
|
||||
|
||||
#endif /* _SBI_ASM_H */
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, Xim
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
#ifndef _ASM_SBI_DEF_H
|
||||
#define _ASM_SBI_DEF_H
|
||||
|
||||
#define SBI_SET_TIMER 0
|
||||
#define SBI_CONSOLE_PUTCHAR 1
|
||||
#define SBI_CONSOLE_GETCHAR 2
|
||||
#define SBI_CLEAR_IPI 3
|
||||
#define SBI_SEND_IPI 4
|
||||
#define SBI_REMOTE_FENCE_I 5
|
||||
#define SBI_REMOTE_SFENCE_VMA 6
|
||||
#define SBI_REMOTE_SFENCE_VMA_ASID 7
|
||||
#define SBI_SHUTDOWN 8
|
||||
|
||||
#define SBI_CONSOLE_PUTSTR 9
|
||||
|
||||
#define SBI_SD_WRITE 10
|
||||
#define SBI_SD_READ 11
|
||||
#define SBI_NET_WRITE 12
|
||||
#define SBI_NET_READ 13
|
||||
|
||||
#endif /* _ASM_SBI_DEF_H */
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-01-29 lizhirui first version
|
||||
* 2021-11-05 JasonHu add c906 cache inst
|
||||
* 2022-11-09 WangXiaoyao Support cache coherence operations;
|
||||
* improve portability and make
|
||||
* no assumption on undefined behavior
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdef.h>
|
||||
#include <board.h>
|
||||
#include <riscv.h>
|
||||
|
||||
#include "opcode.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define L1_CACHE_BYTES (64)
|
||||
|
||||
/**
|
||||
* GCC version not support t-head cache flush, so we use fixed code to achieve.
|
||||
* The following function cannot be optimized.
|
||||
*/
|
||||
static void dcache_wb_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
|
||||
static void dcache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
|
||||
static void dcache_wbinv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
|
||||
static void icache_inv_range(unsigned long start, unsigned long end) __attribute__((optimize("O0")));
|
||||
|
||||
#define CACHE_OP_RS1 %0
|
||||
#define CACHE_OP_RANGE(instr) \
|
||||
{ \
|
||||
register rt_ubase_t i = start & ~(L1_CACHE_BYTES - 1); \
|
||||
for (; i < end; i += L1_CACHE_BYTES) \
|
||||
{ \
|
||||
__asm__ volatile(instr ::"r"(i) \
|
||||
: "memory"); \
|
||||
} \
|
||||
}
|
||||
|
||||
static void dcache_wb_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
CACHE_OP_RANGE(OPC_DCACHE_CVA(CACHE_OP_RS1));
|
||||
}
|
||||
|
||||
static void dcache_inv_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
CACHE_OP_RANGE(OPC_DCACHE_IVA(CACHE_OP_RS1));
|
||||
}
|
||||
|
||||
static void dcache_wbinv_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
CACHE_OP_RANGE(OPC_DCACHE_CIVA(CACHE_OP_RS1));
|
||||
}
|
||||
|
||||
static void icache_inv_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
CACHE_OP_RANGE(OPC_ICACHE_IVA(CACHE_OP_RS1));
|
||||
}
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
|
||||
{
|
||||
return L1_CACHE_BYTES;
|
||||
}
|
||||
|
||||
rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
|
||||
{
|
||||
return L1_CACHE_BYTES;
|
||||
}
|
||||
|
||||
void rt_hw_cpu_icache_invalidate_local(void *addr, int size)
|
||||
{
|
||||
icache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
|
||||
rt_hw_cpu_sync_i();
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_invalidate_local(void *addr, int size)
|
||||
{
|
||||
dcache_inv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean_local(void *addr, int size)
|
||||
{
|
||||
dcache_wb_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size)
|
||||
{
|
||||
dcache_wbinv_range((unsigned long)addr, (unsigned long)((unsigned char *)addr + size));
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* =====================================================
|
||||
* Architecture Independent API
|
||||
* =====================================================
|
||||
*/
|
||||
|
||||
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
|
||||
{
|
||||
if (ops == RT_HW_CACHE_INVALIDATE)
|
||||
{
|
||||
rt_hw_cpu_icache_invalidate_local(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_local(addr, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_cpu_dcache_invalidate_local(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void rt_hw_sync_cache_local(void *addr, int size)
|
||||
{
|
||||
rt_hw_cpu_dcache_clean_local(addr, size);
|
||||
rt_hw_cpu_icache_invalidate_local(addr, size);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_LWP
|
||||
#include <lwp_arch.h>
|
||||
#define ICACHE (1 << 0)
|
||||
#define DCACHE (1 << 1)
|
||||
#define BCACHE (ICACHE | DCACHE)
|
||||
|
||||
/**
|
||||
* TODO moving syscall to kernel
|
||||
*/
|
||||
int sys_cacheflush(void *addr, int size, int cache)
|
||||
{
|
||||
/* must in user space */
|
||||
if ((size_t)addr >= USER_VADDR_START && (size_t)addr + size < USER_VADDR_TOP)
|
||||
{
|
||||
/**
|
||||
* we DO NOT check argument 'cache' invalid error
|
||||
*/
|
||||
if ((cache & DCACHE) != 0)
|
||||
{
|
||||
rt_hw_cpu_dcache_clean_invalidate_local(addr, size);
|
||||
}
|
||||
if ((cache & ICACHE) != 0)
|
||||
{
|
||||
rt_hw_cpu_icache_invalidate_local(addr, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -RT_ERROR;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-11-05 JasonHu The first version
|
||||
*/
|
||||
|
||||
#ifndef CACHE_H__
|
||||
#define CACHE_H__
|
||||
|
||||
#include "opcode.h"
|
||||
|
||||
#ifndef ALWAYS_INLINE
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#define rt_hw_cpu_sync() __asm__ volatile(OPC_SYNC:: \
|
||||
: "memory")
|
||||
|
||||
#define rt_hw_cpu_sync_i() __asm__ volatile(OPC_SYNC_I:: \
|
||||
: "memory");
|
||||
|
||||
/**
|
||||
* ========================================
|
||||
* Local cpu cache maintainence operations
|
||||
* ========================================
|
||||
*/
|
||||
|
||||
void rt_hw_cpu_dcache_clean_local(void *addr, int size);
|
||||
void rt_hw_cpu_dcache_invalidate_local(void *addr, int size);
|
||||
void rt_hw_cpu_dcache_clean_invalidate_local(void *addr, int size);
|
||||
|
||||
void rt_hw_cpu_icache_invalidate_local(void *addr, int size);
|
||||
|
||||
ALWAYS_INLINE void rt_hw_cpu_dcache_clean_all_local(void)
|
||||
{
|
||||
__asm__ volatile(OPC_DCACHE_CALL ::
|
||||
: "memory");
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void rt_hw_cpu_dcache_invalidate_all_local(void)
|
||||
{
|
||||
__asm__ volatile(OPC_DCACHE_IALL ::
|
||||
: "memory");
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void rt_hw_cpu_dcache_clean_invalidate_all_local(void)
|
||||
{
|
||||
__asm__ volatile(OPC_DCACHE_CIALL ::
|
||||
: "memory");
|
||||
rt_hw_cpu_sync();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void rt_hw_cpu_icache_invalidate_all_local(void)
|
||||
{
|
||||
__asm__ volatile(OPC_ICACHE_IALL ::
|
||||
: "memory");
|
||||
rt_hw_cpu_sync_i();
|
||||
}
|
||||
|
||||
/**
|
||||
* ========================================
|
||||
* Multi-core cache maintainence operations
|
||||
* ========================================
|
||||
*/
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#error "TODO: cache maintainence have not ported to RISC-V SMP yet"
|
||||
|
||||
void rt_hw_cpu_dcache_clean(void *addr, int size);
|
||||
void rt_hw_cpu_dcache_invalidate(void *addr, int size);
|
||||
void rt_hw_cpu_dcache_clean_invalidate(void *addr, int size);
|
||||
|
||||
void rt_hw_cpu_dcache_clean_all(void);
|
||||
void rt_hw_cpu_dcache_invalidate_all(void);
|
||||
void rt_hw_cpu_dcache_clean_invalidate_all(void);
|
||||
|
||||
void rt_hw_cpu_icache_invalidate(void *addr, int size);
|
||||
void rt_hw_cpu_icache_invalidate_all(void);
|
||||
|
||||
#else /* !RT_USING_SMP */
|
||||
|
||||
#define rt_hw_cpu_dcache_clean rt_hw_cpu_dcache_clean_local
|
||||
#define rt_hw_cpu_dcache_invalidate rt_hw_cpu_dcache_invalidate_local
|
||||
#define rt_hw_cpu_dcache_clean_invalidate rt_hw_cpu_dcache_clean_invalidate_local
|
||||
|
||||
#define rt_hw_cpu_dcache_clean_all rt_hw_cpu_dcache_clean_all_local
|
||||
#define rt_hw_cpu_dcache_invalidate_all rt_hw_cpu_dcache_invalidate_all_local
|
||||
#define rt_hw_cpu_dcache_clean_invalidate_all rt_hw_cpu_dcache_clean_invalidate_all_local
|
||||
|
||||
#define rt_hw_cpu_icache_invalidate rt_hw_cpu_icache_invalidate_local
|
||||
#define rt_hw_cpu_icache_invalidate_all rt_hw_cpu_icache_invalidate_all_local
|
||||
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
/**
|
||||
* @brief Synchronize cache to Point of Coherent
|
||||
*/
|
||||
void rt_hw_sync_cache_local(void *addr, int size);
|
||||
|
||||
#endif /* CACHE_H__ */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018/10/28 Bernard The unify RISC-V porting implementation
|
||||
* 2018/12/27 Jesven Add SMP support
|
||||
* 2021/02/02 lizhirui Add userspace support
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "cpuport.h"
|
||||
#include "stackframe.h"
|
||||
|
||||
.globl rt_hw_context_switch_to
|
||||
rt_hw_context_switch_to:
|
||||
LOAD sp, (a0)
|
||||
|
||||
la s0, rt_current_thread
|
||||
LOAD s1, (s0)
|
||||
|
||||
#ifdef RT_USING_USERSPACE
|
||||
mv a0, s1
|
||||
jal lwp_mmu_switch
|
||||
#endif
|
||||
|
||||
RESTORE_ALL
|
||||
sret
|
||||
|
||||
/*
|
||||
* void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
|
||||
*
|
||||
* a0 --> from
|
||||
* a1 --> to
|
||||
*/
|
||||
.globl rt_hw_context_switch
|
||||
rt_hw_context_switch:
|
||||
mv t2, sp
|
||||
li t0, 0x120//set SPIE and SPP = 1
|
||||
csrs sstatus, t0//if enter here,caller must be in system thread
|
||||
csrw sepc, ra//return address
|
||||
//saved from thread context
|
||||
SAVE_ALL
|
||||
|
||||
STORE t2, 32 * REGBYTES(sp)//save user_sp
|
||||
|
||||
STORE sp, (a0)
|
||||
|
||||
//restore to thread context
|
||||
LOAD sp, (a1)
|
||||
|
||||
la s0, rt_current_thread
|
||||
LOAD s1, (s0)
|
||||
|
||||
#ifdef RT_USING_USERSPACE
|
||||
mv a0, s1
|
||||
jal lwp_mmu_switch
|
||||
#endif
|
||||
|
||||
RESTORE_ALL
|
||||
sret
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018/10/28 Bernard The unify RISC-V porting code.
|
||||
* 2021-02-11 lizhirui add gp support
|
||||
* 2021-11-19 JasonHu add fpu support
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "cpuport.h"
|
||||
#include "stack.h"
|
||||
|
||||
#include <lwp_arch.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief from thread used interrupt context switch
|
||||
*
|
||||
*/
|
||||
volatile rt_ubase_t rt_interrupt_from_thread = 0;
|
||||
/**
|
||||
* @brief to thread used interrupt context switch
|
||||
*
|
||||
*/
|
||||
volatile rt_ubase_t rt_interrupt_to_thread = 0;
|
||||
/**
|
||||
* @brief flag to indicate context switch in interrupt or not
|
||||
*
|
||||
*/
|
||||
volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct rt_hw_stack_frame *frame;
|
||||
rt_uint8_t *stk;
|
||||
int i;
|
||||
extern int __global_pointer$;
|
||||
|
||||
stk = stack_addr + sizeof(rt_ubase_t);
|
||||
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES);
|
||||
stk -= sizeof(struct rt_hw_stack_frame);
|
||||
|
||||
frame = (struct rt_hw_stack_frame *)stk;
|
||||
|
||||
for (i = 0; i < sizeof(struct rt_hw_stack_frame) / sizeof(rt_ubase_t); i++)
|
||||
{
|
||||
((rt_ubase_t *)frame)[i] = 0xdeadbeef;
|
||||
}
|
||||
|
||||
frame->ra = (rt_ubase_t)texit;
|
||||
frame->gp = (rt_ubase_t)&__global_pointer$;
|
||||
frame->a0 = (rt_ubase_t)parameter;
|
||||
frame->epc = (rt_ubase_t)tentry;
|
||||
frame->user_sp_exc_stack = (rt_ubase_t)(((rt_ubase_t)stk) + sizeof(struct rt_hw_stack_frame));
|
||||
|
||||
/* force to supervisor mode(SPP=1) and set SPIE and SUM to 1 */
|
||||
#ifdef ENABLE_FPU
|
||||
frame->sstatus = 0x00046120; /* enable FPU */
|
||||
#else
|
||||
frame->sstatus = 0x00040120;
|
||||
#endif
|
||||
|
||||
return stk;
|
||||
}
|
||||
|
||||
/*
|
||||
* #ifdef RT_USING_SMP
|
||||
* void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
|
||||
* #else
|
||||
* void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);
|
||||
* #endif
|
||||
*/
|
||||
#ifndef RT_USING_SMP
|
||||
void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
|
||||
{
|
||||
if (rt_thread_switch_interrupt_flag == 0)
|
||||
rt_interrupt_from_thread = from;
|
||||
|
||||
rt_interrupt_to_thread = to;
|
||||
rt_thread_switch_interrupt_flag = 1;
|
||||
|
||||
return ;
|
||||
}
|
||||
#endif /* end of RT_USING_SMP */
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
int rt_hw_cpu_id(void)
|
||||
{
|
||||
return 0; /* d1 has one core */
|
||||
}
|
||||
|
||||
void rt_hw_set_process_id(int pid)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-10-03 Bernard The first version
|
||||
*/
|
||||
|
||||
#ifndef CPUPORT_H__
|
||||
#define CPUPORT_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
#include <opcode.h>
|
||||
|
||||
/* bytes of register width */
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define STORE sd
|
||||
#define LOAD ld
|
||||
#define REGBYTES 8
|
||||
#else
|
||||
// error here, not portable
|
||||
#endif
|
||||
|
||||
/* 33 general register */
|
||||
#define CTX_GENERAL_REG_NR 33
|
||||
|
||||
#ifdef ENABLE_FPU
|
||||
/* 32 fpu register */
|
||||
#define CTX_FPU_REG_NR 32
|
||||
#else
|
||||
#define CTX_FPU_REG_NR 0
|
||||
#endif
|
||||
|
||||
/* all context registers */
|
||||
#define CTX_REG_NR (CTX_GENERAL_REG_NR + CTX_FPU_REG_NR)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
rt_inline void rt_hw_dsb()
|
||||
{
|
||||
asm volatile("fence":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_dmb()
|
||||
{
|
||||
asm volatile("fence":::"memory");
|
||||
}
|
||||
|
||||
rt_inline void rt_hw_isb()
|
||||
{
|
||||
asm volatile(OPC_FENCE_I:::"memory");
|
||||
}
|
||||
|
||||
int rt_hw_cpu_id(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifdef RISCV_U_MODE
|
||||
#define RISCV_USER_ENTRY 0xFFFFFFE000000000ULL
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-19 JasonHu first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "rt_interrupt.h"
|
||||
#include "riscv.h"
|
||||
#include "plic.h"
|
||||
|
||||
extern rt_uint32_t rt_interrupt_nest;
|
||||
extern rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
|
||||
extern rt_uint32_t rt_thread_switch_interrupt_flag;
|
||||
|
||||
struct rt_irq_desc isr_table[INTERRUPTS_MAX];
|
||||
|
||||
static void rt_hw_interrupt_handler(int vector, void *param)
|
||||
{
|
||||
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will initialize hardware interrupt
|
||||
*/
|
||||
void rt_hw_interrupt_init(void)
|
||||
{
|
||||
/* init interrupt controller */
|
||||
plic_init();
|
||||
|
||||
rt_int32_t idx;
|
||||
|
||||
rt_memset(isr_table, 0x00, sizeof(isr_table));
|
||||
for (idx = 0; idx < INTERRUPTS_MAX; idx++)
|
||||
{
|
||||
isr_table[idx].handler = rt_hw_interrupt_handler;
|
||||
}
|
||||
|
||||
/* 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 < 0) || (vector > IRQ_MAX_NR))
|
||||
{
|
||||
return;
|
||||
}
|
||||
plic_disable_irq(vector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* This function will un-mask a interrupt.
|
||||
* @param vector the interrupt number
|
||||
*/
|
||||
void rt_hw_interrupt_umask(int vector)
|
||||
{
|
||||
if ((vector < 0) || (vector > IRQ_MAX_NR))
|
||||
{
|
||||
return;
|
||||
}
|
||||
plic_enable_irq(vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will install a interrupt service routine to a interrupt.
|
||||
* @param vector the interrupt number
|
||||
* @param handler the interrupt service routine to be installed
|
||||
* @param param the interrupt service function parameter
|
||||
* @param name the interrupt name
|
||||
* @return old handler
|
||||
*/
|
||||
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 < 0) || (vector > IRQ_MAX_NR))
|
||||
{
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
old_handler = isr_table[IRQ_OFFSET + vector].handler;
|
||||
|
||||
#ifdef RT_USING_INTERRUPT_INFO
|
||||
rt_strncpy(isr_table[IRQ_OFFSET + vector].name, name, RT_NAME_MAX);
|
||||
#endif /* RT_USING_INTERRUPT_INFO */
|
||||
isr_table[IRQ_OFFSET + vector].handler = handler;
|
||||
isr_table[IRQ_OFFSET + vector].param = param;
|
||||
|
||||
return old_handler;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018/10/02 Bernard The first version
|
||||
* 2018/12/27 Jesven Add SMP schedule
|
||||
* 2021/02/02 lizhirui Add userspace support
|
||||
* 2021/12/24 JasonHu Add user setting save/restore
|
||||
*/
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "cpuport.h"
|
||||
#include "encoding.h"
|
||||
#include "stackframe.h"
|
||||
|
||||
.section .text.entry
|
||||
.align 2
|
||||
.global trap_entry
|
||||
.extern __stack_cpu0
|
||||
.extern get_current_thread_kernel_stack_top
|
||||
trap_entry:
|
||||
//backup sp
|
||||
csrrw sp, sscratch, sp
|
||||
//load interrupt stack
|
||||
la sp, __stack_cpu0
|
||||
//backup context
|
||||
SAVE_ALL
|
||||
|
||||
RESTORE_SYS_GP
|
||||
|
||||
//check syscall
|
||||
csrr t0, scause
|
||||
li t1, 8//environment call from u-mode
|
||||
beq t0, t1, syscall_entry
|
||||
|
||||
csrr a0, scause
|
||||
csrrc a1, stval, zero
|
||||
csrr a2, sepc
|
||||
mv a3, sp
|
||||
|
||||
/* scause, stval, sepc, sp */
|
||||
call handle_trap
|
||||
|
||||
/* need to switch new thread */
|
||||
la s0, rt_thread_switch_interrupt_flag
|
||||
lw s2, 0(s0)
|
||||
beqz s2, spurious_interrupt
|
||||
sw zero, 0(s0)
|
||||
|
||||
.global rt_hw_context_switch_interrupt_do
|
||||
rt_hw_context_switch_interrupt_do:
|
||||
|
||||
//swap to thread kernel stack
|
||||
csrr t0, sstatus
|
||||
andi t0, t0, 0x100
|
||||
beqz t0, __restore_sp_from_tcb_interrupt
|
||||
|
||||
__restore_sp_from_sscratch_interrupt:
|
||||
csrr t0, sscratch
|
||||
j __move_stack_context_interrupt
|
||||
|
||||
__restore_sp_from_tcb_interrupt:
|
||||
la s0, rt_interrupt_from_thread
|
||||
LOAD a0, 0(s0)
|
||||
jal rt_thread_sp_to_thread
|
||||
jal get_thread_kernel_stack_top
|
||||
mv t0, a0
|
||||
|
||||
__move_stack_context_interrupt:
|
||||
mv t1, sp//src
|
||||
mv sp, t0//switch stack
|
||||
addi sp, sp, -CTX_REG_NR * REGBYTES
|
||||
//copy context
|
||||
li s0, CTX_REG_NR//cnt
|
||||
mv t2, sp//dst
|
||||
|
||||
copy_context_loop_interrupt:
|
||||
LOAD t0, 0(t1)
|
||||
STORE t0, 0(t2)
|
||||
addi s0, s0, -1
|
||||
addi t1, t1, 8
|
||||
addi t2, t2, 8
|
||||
bnez s0, copy_context_loop_interrupt
|
||||
|
||||
la s0, rt_interrupt_from_thread
|
||||
LOAD s1, 0(s0)
|
||||
STORE sp, 0(s1)
|
||||
|
||||
la s0, rt_interrupt_to_thread
|
||||
LOAD s1, 0(s0)
|
||||
LOAD sp, 0(s1)
|
||||
|
||||
#ifdef RT_USING_USERSPACE
|
||||
mv a0, s1
|
||||
jal rt_thread_sp_to_thread
|
||||
jal lwp_mmu_switch
|
||||
#endif
|
||||
|
||||
spurious_interrupt:
|
||||
RESTORE_ALL
|
||||
sret
|
||||
|
||||
.global rt_hw_interrupt_enable
|
||||
rt_hw_interrupt_enable:
|
||||
csrs sstatus, a0 /* restore to old csr */
|
||||
jr ra
|
||||
|
||||
.global rt_hw_interrupt_disable
|
||||
rt_hw_interrupt_disable:
|
||||
csrrci a0, sstatus, 2 /* clear SIE */
|
||||
jr ra
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, Xim
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
#ifndef ARCH_IO_H
|
||||
#define ARCH_IO_H
|
||||
#include <rtthread.h>
|
||||
#define RISCV_FENCE(p, s) \
|
||||
__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
|
||||
|
||||
/* These barriers need to enforce ordering on both devices or memory. */
|
||||
#define mb() RISCV_FENCE(iorw,iorw)
|
||||
#define rmb() RISCV_FENCE(ir,ir)
|
||||
#define wmb() RISCV_FENCE(ow,ow)
|
||||
|
||||
#define __arch_getl(a) (*(unsigned int *)(a))
|
||||
#define __arch_putl(v, a) (*(unsigned int *)(a) = (v))
|
||||
|
||||
#define dmb() mb()
|
||||
#define __iormb() rmb()
|
||||
#define __iowmb() wmb()
|
||||
|
||||
static inline void writel(uint32_t val, volatile void *addr)
|
||||
{
|
||||
__iowmb();
|
||||
__arch_putl(val, addr);
|
||||
}
|
||||
|
||||
static inline uint32_t readl(const volatile void *addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = __arch_getl(addr);
|
||||
__iormb();
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void write_reg(
|
||||
uint32_t val, volatile void *addr, unsigned offset)
|
||||
{
|
||||
writel(val, addr + offset);
|
||||
}
|
||||
|
||||
static inline uint32_t read_reg(
|
||||
const volatile void *addr, unsigned offset)
|
||||
{
|
||||
return readl(addr + offset);
|
||||
}
|
||||
|
||||
#endif // ARCH_IO_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-01-30 lizhirui first version
|
||||
*/
|
||||
|
||||
#ifndef __MMU_H__
|
||||
#define __MMU_H__
|
||||
|
||||
#include "riscv.h"
|
||||
#include "riscv_mmu.h"
|
||||
struct mem_desc
|
||||
{
|
||||
rt_size_t vaddr_start;
|
||||
rt_size_t vaddr_end;
|
||||
rt_size_t paddr_start;
|
||||
rt_size_t attr;
|
||||
};
|
||||
|
||||
#define GET_PF_ID(addr) ((addr) >> PAGE_OFFSET_BIT)
|
||||
#define GET_PF_OFFSET(addr) __MASKVALUE(addr,PAGE_OFFSET_MASK)
|
||||
#define GET_L1(addr) __PARTBIT(addr,VPN2_SHIFT,VPN2_BIT)
|
||||
#define GET_L2(addr) __PARTBIT(addr,VPN1_SHIFT,VPN1_BIT)
|
||||
#define GET_L3(addr) __PARTBIT(addr,VPN0_SHIFT,VPN0_BIT)
|
||||
#define GET_PPN(pte) (__PARTBIT(pte,PTE_PPN_SHIFT,PHYSICAL_ADDRESS_WIDTH_BITS - PTE_PPN_SHIFT))
|
||||
#define GET_PADDR(pte) (GET_PPN(pte) << PAGE_OFFSET_BIT)
|
||||
#define VPN_TO_PPN(vaddr,pv_off) (((rt_size_t)(vaddr)) + (pv_off))
|
||||
#define PPN_TO_VPN(paddr,pv_off) (((rt_size_t)(paddr)) - (pv_off))
|
||||
#define COMBINEVADDR(l1_off,l2_off,l3_off) (((l1_off) << VPN2_SHIFT) | ((l2_off) << VPN1_SHIFT) | ((l3_off) << VPN0_SHIFT))
|
||||
#define COMBINEPTE(paddr,attr) ((((paddr) >> PAGE_OFFSET_BIT) << PTE_PPN_SHIFT) | (attr))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t *vtable;
|
||||
size_t vstart;
|
||||
size_t vend;
|
||||
size_t pv_off;
|
||||
}rt_mmu_info;
|
||||
|
||||
void *rt_hw_mmu_tbl_get();
|
||||
void rt_hw_mmu_switch(void *mmu_table);
|
||||
int rt_hw_mmu_map_init(rt_mmu_info *mmu_info,void *v_address,rt_size_t size,rt_size_t *vtable,rt_size_t pv_off);
|
||||
void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info,rt_size_t vaddr_start,rt_size_t size);
|
||||
void *_rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr);
|
||||
void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr);
|
||||
void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size);
|
||||
void *rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr);
|
||||
void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr);
|
||||
void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size);
|
||||
void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr);
|
||||
void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-09 WangXiaoyao Add portable asm support
|
||||
*/
|
||||
#ifndef __OPCODE_H__
|
||||
#define __OPCODE_H__
|
||||
|
||||
/**
|
||||
* @brief binary opcode pseudo operations
|
||||
* Used to bypass toolchain restriction on extension ISA
|
||||
*
|
||||
* WARNING: Xuantie ISAs are not compatible to each other in opcode.
|
||||
* It's painful to port this file, and should be really careful.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief RISC-V instruction formats
|
||||
*/
|
||||
|
||||
/**
|
||||
* R type: .insn r opcode6, func3, func7, rd, rs1, rs2
|
||||
*
|
||||
* +-------+-----+-----+-------+----+---------+
|
||||
* | func7 | rs2 | rs1 | func3 | rd | opcode6 |
|
||||
* +-------+-----+-----+-------+----+---------+
|
||||
* 31 25 20 15 12 7 0
|
||||
*/
|
||||
#define __OPC_INSN_FORMAT_R(opcode, func3, func7, rd, rs1, rs2) \
|
||||
".insn r "RT_STRINGIFY(opcode)","RT_STRINGIFY(func3)","RT_STRINGIFY(func7)","RT_STRINGIFY(rd)","RT_STRINGIFY(rs1)","RT_STRINGIFY(rs2)
|
||||
|
||||
/**
|
||||
* @brief Xuantie T-HEAD extension ISA format
|
||||
* Compatible to Xuantie C906R2S1 user manual v06
|
||||
*/
|
||||
#define __OPC_INSN_FORMAT_CACHE(func7, rs2, rs1) \
|
||||
__OPC_INSN_FORMAT_R(0x0b, 0x0, func7, x0, rs1, rs2)
|
||||
|
||||
#ifdef _TOOLCHAIN_SUPP_XTHEADE_ISA_
|
||||
#define OPC_SYNC "sync"
|
||||
#define OPC_SYNC_I "sync.i"
|
||||
|
||||
#define OPC_DCACHE_CALL "dcache.call"
|
||||
#define OPC_DCACHE_IALL "dcache.iall"
|
||||
#define OPC_DCACHE_CIALL "dcache.ciall"
|
||||
|
||||
#define OPC_ICACHE_IALL "icache.iall"
|
||||
|
||||
#define OPC_DCACHE_CVA(rs1) "dcache.cva "RT_STRINGIFY(rs1)
|
||||
#define OPC_DCACHE_IVA(rs1) "dcache.iva "RT_STRINGIFY(rs1)
|
||||
#define OPC_DCACHE_CIVA(rs1) "dcache.civa "RT_STRINGIFY(rs1)
|
||||
|
||||
#define OPC_ICACHE_IVA(rs1) "icache.iva "RT_STRINGIFY(rs1)
|
||||
#else /* !_TOOLCHAIN_NOT_SUPP_THEAD_ISA_ */
|
||||
#define OPC_SYNC ".long 0x0180000B"
|
||||
#define OPC_SYNC_I ".long 0x01A0000B"
|
||||
|
||||
#define OPC_DCACHE_CALL ".long 0x0010000B"
|
||||
#define OPC_DCACHE_IALL ".long 0x0020000B"
|
||||
#define OPC_DCACHE_CIALL ".long 0x0030000B"
|
||||
|
||||
#define OPC_ICACHE_IALL ".long 0x0100000B"
|
||||
|
||||
#define OPC_DCACHE_CVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x4, rs1)
|
||||
#define OPC_DCACHE_IVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x6, rs1)
|
||||
#define OPC_DCACHE_CIVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x7, rs1)
|
||||
|
||||
#define OPC_ICACHE_IVA(rs1) __OPC_INSN_FORMAT_CACHE(0x1, x16, rs1)
|
||||
#endif /* _TOOLCHAIN_NOT_SUPP_THEAD_ISA_ */
|
||||
|
||||
#ifdef _TOOLCHAIN_SUPP_ZIFENCEI_ISA_
|
||||
#define OPC_FENCE_I "fence.i"
|
||||
#else /* !_TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
|
||||
#define OPC_FENCE_I ".long 0x0000100F"
|
||||
#endif /* _TOOLCHAIN_SUPP_ZIFENCEI_ISA_ */
|
||||
|
||||
#endif /* __OPCODE_H__ */
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-19 JasonHu first version
|
||||
* 2021-11-12 JasonHu fix bug that not intr on f133
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "plic.h"
|
||||
#include "rt_interrupt.h"
|
||||
#include "io.h"
|
||||
#include "encoding.h"
|
||||
|
||||
static void *c906_plic_regs = RT_NULL;
|
||||
|
||||
struct plic_handler
|
||||
{
|
||||
rt_bool_t present;
|
||||
void *hart_base;
|
||||
void *enable_base;
|
||||
};
|
||||
|
||||
rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable);
|
||||
struct plic_handler c906_plic_handlers[C906_NR_CPUS];
|
||||
|
||||
rt_inline void plic_irq_toggle(int hwirq, int enable)
|
||||
{
|
||||
int cpu = 0;
|
||||
|
||||
/* set priority of interrupt, interrupt 0 is zero. */
|
||||
writel(enable, c906_plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
|
||||
struct plic_handler *handler = &c906_plic_handlers[cpu];
|
||||
|
||||
if (handler->present)
|
||||
{
|
||||
plic_toggle(handler, hwirq, enable);
|
||||
}
|
||||
}
|
||||
|
||||
void plic_complete(int irqno)
|
||||
{
|
||||
int cpu = 0;
|
||||
struct plic_handler *handler = &c906_plic_handlers[cpu];
|
||||
|
||||
writel(irqno, handler->hart_base + CONTEXT_CLAIM);
|
||||
}
|
||||
|
||||
void plic_disable_irq(int irqno)
|
||||
{
|
||||
plic_irq_toggle(irqno, 0);
|
||||
}
|
||||
|
||||
void plic_enable_irq(int irqno)
|
||||
{
|
||||
plic_irq_toggle(irqno, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handling an interrupt is a two-step process: first you claim the interrupt
|
||||
* by reading the claim register, then you complete the interrupt by writing
|
||||
* that source ID back to the same claim register. This automatically enables
|
||||
* and disables the interrupt, so there's nothing else to do.
|
||||
*/
|
||||
void plic_handle_irq(void)
|
||||
{
|
||||
int cpu = 0;
|
||||
unsigned int irq;
|
||||
|
||||
struct plic_handler *handler = &c906_plic_handlers[cpu];
|
||||
void *claim = handler->hart_base + CONTEXT_CLAIM;
|
||||
|
||||
if (c906_plic_regs == RT_NULL || !handler->present)
|
||||
{
|
||||
LOG_E("plic state not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
clear_csr(sie, SIE_SEIE);
|
||||
|
||||
while ((irq = readl(claim)))
|
||||
{
|
||||
/* ID0 is diabled permantually from spec. */
|
||||
if (irq == 0)
|
||||
{
|
||||
LOG_E("irq no is zero.");
|
||||
}
|
||||
else
|
||||
{
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
set_csr(sie, SIE_SEIE);
|
||||
}
|
||||
|
||||
rt_inline void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
|
||||
{
|
||||
uint32_t *reg = handler->enable_base + (hwirq / 32) * sizeof(uint32_t);
|
||||
uint32_t hwirq_mask = 1 << (hwirq % 32);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
writel(readl(reg) | hwirq_mask, reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
writel(readl(reg) & ~hwirq_mask, reg);
|
||||
}
|
||||
}
|
||||
|
||||
void plic_init(void)
|
||||
{
|
||||
int nr_irqs;
|
||||
int nr_context;
|
||||
int i;
|
||||
unsigned long hwirq;
|
||||
int cpu = 0;
|
||||
|
||||
if (c906_plic_regs)
|
||||
{
|
||||
LOG_E("plic already initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
nr_context = C906_NR_CONTEXT;
|
||||
|
||||
c906_plic_regs = (void *)C906_PLIC_PHY_ADDR;
|
||||
if (!c906_plic_regs)
|
||||
{
|
||||
LOG_E("fatal error, plic is reg space is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
nr_irqs = C906_PLIC_NR_EXT_IRQS;
|
||||
|
||||
for (i = 0; i < nr_context; i ++)
|
||||
{
|
||||
struct plic_handler *handler;
|
||||
uint32_t threshold = 0;
|
||||
|
||||
cpu = 0;
|
||||
|
||||
/* skip contexts other than supervisor external interrupt */
|
||||
if (i == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// we always use CPU0 M-mode target register.
|
||||
handler = &c906_plic_handlers[cpu];
|
||||
if (handler->present)
|
||||
{
|
||||
threshold = 0xffffffff;
|
||||
goto done;
|
||||
}
|
||||
|
||||
handler->present = RT_TRUE;
|
||||
handler->hart_base = c906_plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
|
||||
handler->enable_base = c906_plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
|
||||
done:
|
||||
/* priority must be > threshold to trigger an interrupt */
|
||||
writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
|
||||
for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
|
||||
{
|
||||
plic_toggle(handler, hwirq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable supervisor external interrupts. */
|
||||
set_csr(sie, SIE_SEIE);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-19 JasonHu first version
|
||||
*/
|
||||
|
||||
#ifndef __RISCV64_PLIC_H__
|
||||
#define __RISCV64_PLIC_H__
|
||||
|
||||
#include <rt_interrupt.h>
|
||||
|
||||
#define C906_PLIC_PHY_ADDR (0x10000000)
|
||||
#define C906_PLIC_NR_EXT_IRQS (IRQ_MAX_NR)
|
||||
#define C906_NR_CPUS (NR_CPUS)
|
||||
|
||||
/* M and S mode context. */
|
||||
#define C906_NR_CONTEXT (2)
|
||||
|
||||
#define MAX_DEVICES 1024
|
||||
#define MAX_CONTEXTS 15872
|
||||
|
||||
/*
|
||||
* Each interrupt source has a priority register associated with it.
|
||||
* We always hardwire it to one in Linux.
|
||||
*/
|
||||
#define PRIORITY_BASE 0
|
||||
#define PRIORITY_PER_ID 4
|
||||
|
||||
/*
|
||||
* Each hart context has a vector of interrupt enable bits associated with it.
|
||||
* There's one bit for each interrupt source.
|
||||
*/
|
||||
#define ENABLE_BASE 0x2000
|
||||
#define ENABLE_PER_HART 0x80
|
||||
|
||||
/*
|
||||
* Each hart context has a set of control registers associated with it. Right
|
||||
* now there's only two: a source priority threshold over which the hart will
|
||||
* take an interrupt, and a register to claim interrupts.
|
||||
*/
|
||||
#define CONTEXT_BASE 0x200000
|
||||
#define CONTEXT_PER_HART 0x1000
|
||||
#define CONTEXT_THRESHOLD 0x00
|
||||
#define CONTEXT_CLAIM 0x04
|
||||
|
||||
void plic_init(void);
|
||||
void plic_enable_irq(int irqno);
|
||||
void plic_disable_irq(int irqno);
|
||||
// tell PLIC that we've served this IRQ
|
||||
void plic_complete(int irq);
|
||||
void plic_handle_irq(void);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user