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:
guo
2022-12-03 12:07:44 +08:00
committed by GitHub
co-authored by Rbb666 zhkag
parent aaf5462c6d
commit ecf2d82159
1693 changed files with 389530 additions and 9680 deletions
+57 -1
View File
@@ -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
+10
View File
@@ -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");
+23
View File
@@ -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__*/
+13
View File
@@ -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__*/
-63
View File
@@ -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
+2 -2
View File
@@ -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
+83
View File
@@ -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
View File
@@ -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
+92 -9
View File
@@ -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
+3 -5
View File
@@ -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__*/
+5 -1
View File
@@ -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;
+10
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+65 -1
View File
@@ -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
+6 -2
View File
@@ -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));
}
+2 -2
View File
@@ -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
*/
/*@{*/
File diff suppressed because it is too large Load Diff
+177 -101
View File
@@ -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)
+6
View File
@@ -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
+23
View File
@@ -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__*/
+23
View File
@@ -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__*/
+23
View File
@@ -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__*/
+23
View File
@@ -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__*/
+23
View File
@@ -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__*/
+3 -1
View File
@@ -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'))
+1
View File
@@ -10,6 +10,7 @@
* 2020/11/20 BalanceTWK Add FPU support
*/
#define __ASSEMBLY__
#include "cpuport.h"
#ifdef RT_USING_SMP
+1 -1
View File
@@ -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;
+12
View File
@@ -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
+1
View File
@@ -9,6 +9,7 @@
* 2018/12/27 Jesven Add SMP schedule
*/
#define __ASSEMBLY__
#include "cpuport.h"
.section .text.entry
+1
View File
@@ -9,6 +9,7 @@
* 2018/12/27 Jesven Add SMP support
*/
#define __ASSEMBLY__
#define MSTATUS_FS 0x00006000U /* initial state of FPU */
#include <cpuport.h>
+12
View File
@@ -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')
+10
View File
@@ -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 */
+27
View File
@@ -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 */
+160
View File
@@ -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
+106
View File
@@ -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__ */
+63
View File
@@ -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
+127
View File
@@ -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
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 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
+105
View File
@@ -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;
}
+114
View File
@@ -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
+52
View File
@@ -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
+57
View File
@@ -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
+81
View File
@@ -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__ */
+177
View File
@@ -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);
}
+57
View File
@@ -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