diff options
Diffstat (limited to 'bsp/ultrarisc/arch')
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/SConscript | 12 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/cache.c | 45 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/cache.h | 92 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/interrupt.c | 92 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/interrupt.h | 46 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/opcode.h | 40 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/plic.c | 255 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/plic.h | 81 | ||||
| -rw-r--r-- | bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h | 195 |
9 files changed, 858 insertions, 0 deletions
diff --git a/bsp/ultrarisc/arch/ur-cp100/SConscript b/bsp/ultrarisc/arch/ur-cp100/SConscript new file mode 100644 index 0000000000..640ac340f6 --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/SConscript @@ -0,0 +1,12 @@ +# RT-Thread building script for component + +from building import * +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('arch', src, depend = [''], CPPPATH = CPPPATH) + +objs = [group] + +Return('objs') diff --git a/bsp/ultrarisc/arch/ur-cp100/cache.c b/bsp/ultrarisc/arch/ur-cp100/cache.c new file mode 100644 index 0000000000..57f47e7bed --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/cache.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-29 lizhirui first version + * 2025-05-29 Zhang Jing remove redundant code + */ + +#include <rthw.h> +#include <rtdef.h> +#include <board.h> +#include <riscv.h> +#include <cache.h> + +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); + } + return; +} + +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 + { + rt_hw_cpu_dcache_invalidate(addr, size); + } + return; +} + +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); + return; +}
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/cache.h b/bsp/ultrarisc/arch/ur-cp100/cache.h new file mode 100644 index 0000000000..55d532f958 --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/cache.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-09 RT-Thread The first version + */ +#ifndef __CACHE_H__ +#define __CACHE_H__ + +#include <rtdef.h> + +/** + * @brief These APIs may not be supported by a specified architecture + * But we have to include to all the cases to be 'general purpose' + */ + +rt_always_inline void rt_hw_cpu_dcache_clean_local(void *addr, int size) +{ + RT_UNUSED(addr); + RT_UNUSED(size); +} + +rt_always_inline void rt_hw_cpu_dcache_invalidate_local(void *addr, int size) +{ + RT_UNUSED(addr); + RT_UNUSED(size); +} + +rt_always_inline void rt_hw_cpu_dcache_clean_and_invalidate_local(void *addr, int size) +{ + RT_UNUSED(addr); + RT_UNUSED(size); +} + +rt_always_inline void rt_hw_cpu_dcache_clean_all_local(void) +{ +} + +rt_always_inline void rt_hw_cpu_dcache_invalidate_all_local(void) +{ +} + +rt_always_inline void rt_hw_cpu_dcache_clean_and_invalidate_all_local(void) +{ +} + +/*use fence.i to invalidate all icache*/ +rt_always_inline void rt_hw_cpu_icache_invalidate_local(void *addr, int size) +{ + __asm__ __volatile__("fence.i" ::: "memory"); +} +/*use fence.i to invalidate all icache*/ +rt_always_inline void rt_hw_cpu_icache_invalidate_all_local(void) +{ + __asm__ __volatile__("fence.i" ::: "memory"); +} + +/** + * @brief Multi-core + */ + +#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_and_invalidate rt_hw_cpu_dcache_clean_and_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_and_invalidate_all rt_hw_cpu_dcache_clean_and_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 + +#define rt_hw_icache_invalidate_all rt_hw_cpu_icache_invalidate_all + +/** instruction barrier */ +static inline void rt_hw_cpu_sync(void) +{ + __asm__ __volatile__("fence.i" ::: "memory"); +} + +/** + * @brief local cpu icahce & dcache synchronization + * + * @param addr + * @param size + */ +void rt_hw_sync_cache_local(void *addr, int size); + +#endif /* __CACHE_H__ */
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/interrupt.c b/bsp/ultrarisc/arch/ur-cp100/interrupt.c new file mode 100644 index 0000000000..67947cd627 --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/interrupt.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018/10/01 Bernard The first version + * 2018/12/27 Jesven Change irq enable/disable to cpu0 + */ +#include <plic.h> +#include "encoding.h" +#include "riscv.h" +#include "interrupt.h" + +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param) +{ + rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector); + return RT_NULL; +} + +int rt_hw_plic_irq_enable(int irq_number) +{ + plic_irq_enable(irq_number); + return 0; +} + +int rt_hw_plic_irq_disable(int irq_number) +{ + plic_irq_disable(irq_number); + return 0; +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + plic_set_priority(vector, 1); + + rt_hw_plic_irq_enable(vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = (rt_isr_handler_t)handler; + irq_desc[vector].param = param; +#ifdef RT_USING_INTERRUPT_INFO + rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name); + irq_desc[vector].counter = 0; +#endif + } + } + + return old_handler; +} + +void rt_hw_interrupt_init() +{ + /* Enable machine external interrupts. */ + /* set_csr(sie, SIP_SEIP); */ + int idx = 0; + /* init exceptions table */ + for (idx = 0; idx < MAX_HANDLERS; idx++) + { + irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle; + irq_desc[idx].param = RT_NULL; +#ifdef RT_USING_INTERRUPT_INFO + rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default"); + irq_desc[idx].counter = 0; +#endif + } + /*init plic*/ + plic_init(); +}
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/interrupt.h b/bsp/ultrarisc/arch/ur-cp100/interrupt.h new file mode 100644 index 0000000000..cda387087a --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/interrupt.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-05-20 bigmagic The first version + */ + +#ifndef INTERRUPT_H__ +#define INTERRUPT_H__ + +#define MAX_HANDLERS 128 + +#include <rthw.h> +#include "stack.h" + +enum +{ + EP_INSTRUCTION_ADDRESS_MISALIGNED = 0, + EP_INSTRUCTION_ACCESS_FAULT, + EP_ILLEGAL_INSTRUCTION, + EP_BREAKPOINT, + EP_LOAD_ADDRESS_MISALIGNED, + EP_LOAD_ACCESS_FAULT, + EP_STORE_ADDRESS_MISALIGNED, + EP_STORE_ACCESS_FAULT, + EP_ENVIRONMENT_CALL_U_MODE, + EP_ENVIRONMENT_CALL_S_MODE, + EP_RESERVED10, + EP_ENVIRONMENT_CALL_M_MODE, + EP_INSTRUCTION_PAGE_FAULT, /* page attr */ + EP_LOAD_PAGE_FAULT, /* read data */ + EP_RESERVED14, + EP_STORE_PAGE_FAULT, /* write data */ +}; + +int rt_hw_plic_irq_enable(int irq_number); +int rt_hw_plic_irq_disable(int irq_number); +void rt_hw_interrupt_init(void); +void rt_hw_interrupt_mask(int vector); +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name); +void handle_trap(rt_size_t xcause, rt_size_t xtval, rt_size_t xepc, struct rt_hw_stack_frame *sp); + +#endif
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/opcode.h b/bsp/ultrarisc/arch/ur-cp100/opcode.h new file mode 100644 index 0000000000..8bdf4afe35 --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/opcode.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-09 Shell Add portable asm support + */ +#ifndef __OPCODE_H__ +#define __OPCODE_H__ + +/** + * @brief binary opcode pseudo operations + * Used to bypass toolchain restriction on extension ISA + * + */ + +/** + * @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) + +#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__ */
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/plic.c b/bsp/ultrarisc/arch/ur-cp100/plic.c new file mode 100644 index 0000000000..7317b5b85e --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/plic.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Support for RISC-V Platform-Level Interrupt Controller(PLIC) + * Specification Version 1.0.0, which is currently(3/12/2023) the + * lastest draft. + * + * Change Logs: + * Date Author Notes + * 2021-05-20 bigmagic first version + * 2022-09-16 WangXiaoyao Porting to rv64 + * 2025-01-26 ZhangJing Porting to ultrarisc cp100 + */ +#include <rthw.h> +#include <rtthread.h> +#include <stdint.h> +#include "plic.h" +#include <io.h> +#include "encoding.h" +#include <interrupt.h> +#include <riscv_io.h> +#include <riscv.h> +#include <string.h> +#include <stdlib.h> + +#ifdef RT_USING_SMART + #include <ioremap.h> +#else + #define rt_ioremap(addr, ...) (addr) +#endif + +/* plic_base should be initialized in the bsp*/ +size_t plic_base = 0 ; + +/* + * Each PLIC interrupt source can be assigned a priority by writing + * to its 32-bit memory-mapped priority register. + * Maximum priority is 7. + * A priority value of 0 is reserved to mean "never interrupt" and + * effectively disables the interrupt. + * Ties between global interrupts of the same priority are broken by + * the Interrupt ID; interrupts with the lowest ID have the highest + * effective priority. + */ +void plic_set_priority(int irq, int priority) +{ + writel(priority, (void *)PLIC_PRIORITY(irq)); +} + +/* + * Each global interrupt can be enabled by setting the corresponding + * bit in the enables registers. + */ +void plic_irq_enable(int irq) +{ + int hart = __raw_hartid(); + void *enable = (void *)PLIC_ENABLE(hart) + (irq / 32) * sizeof(uint32_t); + rt_uint32_t val = readl(enable); + val |= (1 << (irq % 32)); + writel(val, enable); + return; +} + +/* + * Each global interrupt can be disabled by clearing the corresponding + * bit in the enables registers. + */ +void plic_irq_disable(int irq) +{ + int hart = __raw_hartid(); + void *enable = (void *)PLIC_ENABLE(hart) + (irq / 32) * sizeof(uint32_t); + rt_uint32_t val = readl(enable); + val &= ~(1 << (irq % 32)); + writel(val, enable); + + return; +} + +/* + * PLIC will mask all interrupts of a priority less than or equal to threshold. + * Maximum threshold is 7. + * For example, a threshold value of zero permits all interrupts with + * non-zero priority, whereas a value of 7 masks all interrupts. + * Notice, the threshold is global for PLIC, not for each interrupt source. + */ +void plic_set_threshold(int threshold) +{ + int hart = __raw_hartid(); + writel(threshold, (void *)PLIC_THRESHOLD(hart)); + return; +} + +/* + * DESCRIPTION: + * Query the PLIC what interrupt we should serve. + * Perform an interrupt claim by reading the claim register, which + * returns the ID of the highest-priority pending interrupt or zero if there + * is no pending interrupt. + * A successful claim also atomically clears the corresponding pending bit + * on the interrupt source. + * RETURN VALUE: + * the ID of the highest-priority pending interrupt or zero if there + * is no pending interrupt. + */ +rt_uint32_t plic_claim(void) +{ + int hart = __raw_hartid(); + void *claim = (void *)PLIC_CLAIM(hart); + return readl(claim); +} + +/* + * DESCRIPTION: + * Writing the interrupt ID it received from the claim (irq) to the + * complete register would signal the PLIC we've served this IRQ. + * The PLIC does not check whether the completion ID is the same as the + * last claim ID for that target. If the completion ID does not match an + * interrupt source that is currently enabled for the target, the completion + * is silently ignored. + * RETURN VALUE: none + */ +void plic_complete(int irq) +{ + int hart = __raw_hartid(); + void *complete = (void *)PLIC_COMPLETE(hart); + writel(irq, complete); + return; +} + +void plic_init() +{ + if (!plic_base) + { + return; + } + /* PLIC takes up 64 MB space */ + plic_base = (size_t)rt_ioremap((void *)plic_base, 64 * 1024 * 1024); + + plic_set_threshold(0); + + /*set the same priority for all the irqs*/ + for (int i = 1; i < CONFIG_IRQ_NR; i++) + { + plic_set_priority(i, 1); + } + + /*disable all interrupts*/ + for (int i = 1; i < CONFIG_IRQ_NR; i++) + { + plic_irq_disable(i); + } + + set_csr(sie, read_csr(sie) | MIP_SEIP); + + return; +} + +extern struct rt_irq_desc irq_desc[MAX_HANDLERS]; +#ifdef BOARD_UR_DP1000 +int find_first_bit(rt_uint32_t *addr, int size) +{ + int i; + for (i = 0; i < size; i++) + { + if (*addr & (1 << i)) + return i; + } + return -1; +} + +static rt_bool_t is_irqs_pending(rt_uint32_t ie[]) +{ + + int hartid = __raw_hartid(); + int nr_irqs = CONFIG_IRQ_NR; + int nr_irq_groups = (nr_irqs + 31) / 32; + rt_bool_t is_pending = RT_FALSE; + void *pending_base = (void *)PLIC_PENDING(0); + void *enable_base = (void *)PLIC_ENABLE(hartid); + int i, j; + + for (i = 0; i < nr_irq_groups; i++) + ie[i] = readl(enable_base + i * sizeof(rt_uint32_t)); + + for (i = 0; i < nr_irq_groups; i++) + { + rt_uint32_t pending_irqs = readl(pending_base + i * sizeof(rt_uint32_t)) & ie[i]; + if (pending_irqs) + { + int nbit = find_first_bit(&pending_irqs, 32); + for (j = 0; j < nr_irq_groups; j++) + writel((i == j) ? (1 << nbit) : 0, enable_base + j * sizeof(rt_uint32_t)); + + is_pending = RT_TRUE; + break; + } + } + + return is_pending; +} + +static void restore_irqs_enable(rt_uint32_t ie[]) +{ + int hartid = __raw_hartid(); + int nr_irqs = CONFIG_IRQ_NR; + int nr_irq_groups = (nr_irqs + 31) / 32; + void *enable_base = (void *)PLIC_ENABLE(hartid); + int i; + + for (i = 0; i < nr_irq_groups; i++) + writel(ie[i], enable_base + i * sizeof(rt_uint32_t)); + + return; +} +#endif +/* + * 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) +{ + rt_uint32_t plic_irq; +#ifdef BOARD_UR_DP1000 + /* TODO: if not only one interrupt, we need to continue to check the interrupt source */ + unsigned int ie[32] = {0}; + plic_irq = is_irqs_pending(ie) ? plic_claim() : 0; + restore_irqs_enable(ie); + if (plic_irq > CONFIG_IRQ_NR) + { + /*spurious interrupt, return directly*/ + rt_kprintf("spurious interrupt, irq = %d\n", plic_irq); + return; + } + plic_complete(plic_irq); + + irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param); + +#else + plic_irq = plic_claim(); + plic_complete(plic_irq); + if (plic_irq > CONFIG_IRQ_NR) + { + /*spurious interrupt, return directly*/ + rt_kprintf("spurious interrupt, irq = %d\n", plic_irq); + return; + } + + irq_desc[plic_irq].handler(plic_irq, irq_desc[plic_irq].param); +#endif + return; +}
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/plic.h b/bsp/ultrarisc/arch/ur-cp100/plic.h new file mode 100644 index 0000000000..050a24d7bb --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/plic.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-05-20 bigmagic first version + * 2021-10-20 bernard fix s-mode issue + * 2025-01-26 ZhangJing Porting to ultrarisc cp100 + */ + +#ifndef __PLIC_H__ +#define __PLIC_H__ + +#include <rtconfig.h> +#include <rthw.h> + +#define PLIC_PRIORITY_BASE 0x0 +#define PLIC_PENDING_BASE 0x1000 +#define PLIC_ENABLE_BASE 0x2000 +#define PLIC_CONTEXT_BASE 0x200000 + +extern size_t plic_base; + +#define PLIC_BASE (plic_base) + +#define PLIC_PRIORITY_OFFSET (0x0) +#define PLIC_PENDING_OFFSET (0x1000) + +#define PLIC_ENABLE_STRIDE 0x80 +#define PLIC_CONTEXT_STRIDE 0x1000 + +#define RISCV_S_MODE + +#ifndef RISCV_S_MODE + /*using context 0*/ + #define PLIC_MENABLE_OFFSET (0x2000) + #define PLIC_MTHRESHOLD_OFFSET (0x200000) + #define PLIC_MCLAIM_OFFSET (0x200004) + #define PLIC_MCOMPLETE_OFFSET (0x200004) + + #define PLIC_ENABLE(hart) (PLIC_BASE + PLIC_MENABLE_OFFSET + (hart * 3) * PLIC_ENABLE_STRIDE) + #define PLIC_THRESHOLD(hart) (PLIC_BASE + PLIC_MTHRESHOLD_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) + #define PLIC_CLAIM(hart) (PLIC_BASE + PLIC_MCLAIM_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) + #define PLIC_COMPLETE(hart) (PLIC_BASE + PLIC_MCOMPLETE_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) + +#else + /*using context 1*/ + #define PLIC_SENABLE_OFFSET (0x2000 + PLIC_ENABLE_STRIDE) + #define PLIC_STHRESHOLD_OFFSET (0x200000 + PLIC_CONTEXT_STRIDE) + #define PLIC_SCLAIM_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE) + #define PLIC_SCOMPLETE_OFFSET (0x200004 + PLIC_CONTEXT_STRIDE) + + #define PLIC_ENABLE(hart) (PLIC_BASE + PLIC_SENABLE_OFFSET + (hart * 3) * PLIC_ENABLE_STRIDE) + #define PLIC_THRESHOLD(hart) (PLIC_BASE + PLIC_STHRESHOLD_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) + #define PLIC_CLAIM(hart) (PLIC_BASE + PLIC_SCLAIM_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) + #define PLIC_COMPLETE(hart) (PLIC_BASE + PLIC_SCOMPLETE_OFFSET + (hart * 3) * PLIC_CONTEXT_STRIDE) +#endif + +#define PLIC_PRIORITY(id) (PLIC_BASE + PLIC_PRIORITY_OFFSET + (id) * 4) +#define PLIC_PENDING(id) (PLIC_BASE + PLIC_PENDING_OFFSET + ((id) / 32)) + +#define WORD_CNT_BYTE (1024 / 8) + +#define CONFIG_IRQ_NR (32) +#define CONFIG_IRQ_WORD (CONFIG_IRQ_NR / 32) + +void plic_set_priority(int irq, int priority); +void plic_irq_enable(int irq); +void plic_irq_disable(int irq); +void plic_set_threshold(int mthreshold); +rt_uint32_t plic_claim(void); +void plic_complete(int irq); + +void plic_set_thresh(rt_uint32_t val); +void plic_set_ie(rt_uint32_t word_index, rt_uint32_t val); +void plic_init(); +void plic_handle_irq(void); + +#endif
\ No newline at end of file diff --git a/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h b/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h new file mode 100644 index 0000000000..1048d4bb40 --- /dev/null +++ b/bsp/ultrarisc/arch/ur-cp100/riscv_mmu.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-30 lizhirui first version + * 2023-10-12 Shell Add permission control API + * 2025-01-22 ZhangJing Add pte default attribute for ur-cp100 + */ + +#ifndef __RISCV_MMU_H__ +#define __RISCV_MMU_H__ + +#include <rtthread.h> +#include <rthw.h> +#include "riscv.h" + +#undef PAGE_SIZE + +#define PAGE_OFFSET_SHIFT 0 +#define PAGE_OFFSET_BIT 12 +#define PAGE_SIZE __SIZE(PAGE_OFFSET_BIT) +#define PAGE_OFFSET_MASK __MASK(PAGE_OFFSET_BIT) +#define VPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT) +#define VPN0_BIT 9 +#define VPN1_SHIFT (VPN0_SHIFT + VPN0_BIT) +#define VPN1_BIT 9 +#define VPN2_SHIFT (VPN1_SHIFT + VPN1_BIT) +#define VPN2_BIT 9 + +#define PPN0_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT) +#define PPN0_BIT 9 +#define PPN1_SHIFT (PPN0_SHIFT + PPN0_BIT) +#define PPN1_BIT 9 +#define PPN2_SHIFT (PPN1_SHIFT + PPN1_BIT) +#define PPN2_BIT 26 +#define PPN_BITS (PPN0_BIT + PPN1_BIT + PPN2_BIT) + +#define L1_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT + VPN1_BIT) +#define L2_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT + VPN0_BIT) +#define L3_PAGE_SIZE __SIZE(PAGE_OFFSET_BIT) + +#define ARCH_ADDRESS_WIDTH_BITS 64 + +#define PHYSICAL_ADDRESS_WIDTH_BITS 56 + +#define PAGE_ATTR_BASE (PTE_A | PTE_D) +#define PAGE_ATTR_NEXT_LEVEL (0) +#define PAGE_ATTR_RWX (PTE_X | PTE_W | PTE_R) +#define PAGE_ATTR_READONLY (PTE_R) +#define PAGE_ATTR_READEXECUTE (PTE_X | PTE_R) + +#define PAGE_ATTR_USER (PTE_U) +#define PAGE_ATTR_SYSTEM (0) + +#define PAGE_DEFAULT_ATTR_LEAF (PAGE_ATTR_RWX | PAGE_ATTR_USER | PTE_V | PTE_G | PAGE_ATTR_BASE ) +#define PAGE_DEFAULT_ATTR_NEXT (PAGE_ATTR_NEXT_LEVEL | PTE_V | PTE_G) + +#define PAGE_IS_LEAF(pte) __MASKVALUE(pte, PAGE_ATTR_RWX) + +#define PTE_USED(pte) __MASKVALUE(pte, PTE_V) + +/** + * encoding of SATP (Supervisor Address Translation and Protection register) + */ +#define SATP_MODE_OFFSET 60 +#define SATP_MODE_BARE 0 +#define SATP_MODE_SV39 8 +#define SATP_MODE_SV48 9 +#define SATP_MODE_SV57 10 +#define SATP_MODE_SV64 11 + +#define ARCH_VADDR_WIDTH 39 +#define SATP_MODE SATP_MODE_SV39 + +#define MMU_MAP_K_DEVICE (PTE_G | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_K_RWCB (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_K_RW (PTE_G | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_U_RWCB (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_U_RWCB_XN (PTE_U | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_U_RW (PTE_U | PTE_X | PTE_W | PTE_R | PTE_V | PAGE_ATTR_BASE) +#define MMU_MAP_EARLY (PAGE_ATTR_RWX | PTE_G | PTE_V | PAGE_ATTR_BASE) + +#define PTE_XWR_MASK 0xe + +#define ARCH_PAGE_SIZE PAGE_SIZE +#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1) +#define ARCH_PAGE_SHIFT PAGE_OFFSET_BIT +#define ARCH_INDEX_WIDTH 9 +#define ARCH_INDEX_SIZE (1ul << ARCH_INDEX_WIDTH) +#define ARCH_INDEX_MASK (ARCH_INDEX_SIZE - 1) + +#define DRAM_SIZE (0x400000000) /* 16GB */ +#define MMIO_SIZE (0x80000000) +#define MAP_COUNT ((DRAM_SIZE + MMIO_SIZE) >> VPN2_SHIFT) + +#define ARCH_MAP_FAILED ((void *)0x8000000000000000) + +void mmu_set_pagetable(rt_ubase_t addr); +void mmu_enable_user_page_access(void); +void mmu_disable_user_page_access(void); + +#define RT_HW_MMU_PROT_READ 1 +#define RT_HW_MMU_PROT_WRITE 2 +#define RT_HW_MMU_PROT_EXECUTE 4 +#define RT_HW_MMU_PROT_KERNEL 8 +#define RT_HW_MMU_PROT_USER 16 +#define RT_HW_MMU_PROT_CACHE 32 + +void rt_hw_asid_init(void); +struct rt_aspace; +void rt_hw_asid_switch_pgtbl(struct rt_aspace *aspace, rt_ubase_t pgtbl); + +/** + * @brief Remove permission from attribution + * + * @param attr architecture specified mmu attribution + * @param prot protect that will be removed + * @return size_t returned attribution + */ +rt_inline size_t rt_hw_mmu_attr_rm_perm(size_t attr, rt_base_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + attr &= ~PTE_W; + break; + /* remove write permission for kernel */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL: + attr &= ~PTE_W; + break; + default: + RT_ASSERT(0); + } + return attr; +} + +/** + * @brief Add permission from attribution + * + * @param attr architecture specified mmu attribution + * @param prot protect that will be added + * @return size_t returned attribution + */ +rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot) +{ + switch (prot) + { + /* add write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + attr |= (PTE_R | PTE_W | PTE_U); + break; + default: + RT_ASSERT(0); + } + return attr; +} + +/** + * @brief Test permission from attribution + * + * @param attr architecture specified mmu attribution + * @param prot protect that will be test + * @return rt_bool_t RT_TRUE if the prot is allowed, otherwise RT_FALSE + */ +rt_inline rt_bool_t rt_hw_mmu_attr_test_perm(size_t attr, rt_base_t prot) +{ + rt_bool_t rc = 0; + switch (prot & ~RT_HW_MMU_PROT_USER) + { + /* test write permission for user */ + case RT_HW_MMU_PROT_WRITE: + rc = ((attr & PTE_W) && (attr & PTE_R)); + break; + case RT_HW_MMU_PROT_READ: + rc = !!(attr & PTE_R); + break; + case RT_HW_MMU_PROT_EXECUTE: + rc = !!(attr & PTE_X); + break; + default: + RT_ASSERT(0); + } + + if (rc && (prot & RT_HW_MMU_PROT_USER)) + { + rc = !!(attr & PTE_U); + } + return rc; +} + +#endif
\ No newline at end of file |
