diff options
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/aarch64/common/cpu.h | 4 | ||||
| -rw-r--r-- | libcpu/aarch64/common/exception.c | 10 | ||||
| -rw-r--r-- | libcpu/aarch64/common/mmu.c | 27 | ||||
| -rw-r--r-- | libcpu/aarch64/common/mmu.h | 108 | ||||
| -rw-r--r-- | libcpu/aarch64/common/trap.c | 82 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a/entry_point.S | 8 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a/mmu.c | 25 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a/mmu.h | 119 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a/trap.c | 62 | ||||
| -rw-r--r-- | libcpu/risc-v/t-head/c906/mmu.c | 20 | ||||
| -rw-r--r-- | libcpu/risc-v/t-head/c906/mmu.h | 4 | ||||
| -rw-r--r-- | libcpu/risc-v/t-head/c906/riscv_mmu.h | 70 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/mmu.c | 20 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/mmu.h | 4 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/riscv_mmu.h | 71 |
15 files changed, 561 insertions, 73 deletions
diff --git a/libcpu/aarch64/common/cpu.h b/libcpu/aarch64/common/cpu.h index e3efaec485..873207d91b 100644 --- a/libcpu/aarch64/common/cpu.h +++ b/libcpu/aarch64/common/cpu.h @@ -13,10 +13,6 @@ #include <rtthread.h> #include <stdbool.h> -#ifndef RT_CPUS_NR -#define RT_CPUS_NR 1 -#endif /* RT_CPUS_NR */ - #ifdef RT_USING_SMP struct cpu_ops_t { diff --git a/libcpu/aarch64/common/exception.c b/libcpu/aarch64/common/exception.c index 7da19c0e6e..7582c2a0ce 100644 --- a/libcpu/aarch64/common/exception.c +++ b/libcpu/aarch64/common/exception.c @@ -54,6 +54,10 @@ static void data_abort(unsigned long far, unsigned long iss) rt_kprintf("Translation fault, third level\n"); break; + case 0b001000: + rt_kprintf("Access flag fault, zeroth level\n"); + break; + case 0b001001: rt_kprintf("Access flag fault, first level\n"); break; @@ -66,6 +70,10 @@ static void data_abort(unsigned long far, unsigned long iss) rt_kprintf("Access flag fault, third level\n"); break; + case 0b001100: + rt_kprintf("Permission fault, zeroth level\n"); + break; + case 0b001101: rt_kprintf("Permission fault, first level\n"); break; @@ -148,7 +156,7 @@ static void data_abort(unsigned long far, unsigned long iss) } } -void process_exception(unsigned long esr, unsigned long epc) +void print_exception(unsigned long esr, unsigned long epc) { rt_uint8_t ec; rt_uint32_t iss; diff --git a/libcpu/aarch64/common/mmu.c b/libcpu/aarch64/common/mmu.c index e8a0bfeefb..1426dc7fef 100644 --- a/libcpu/aarch64/common/mmu.c +++ b/libcpu/aarch64/common/mmu.c @@ -204,7 +204,7 @@ static int _kernel_map_2M(unsigned long *lv0_tbl, void *vaddr, void *paddr, unsi { return MMU_MAP_ERROR_VANOTALIGN; } - if (pa & ARCH_SECTION_MASK) + if (pa & ARCH_PAGE_MASK) { return MMU_MAP_ERROR_PANOTALIGN; } @@ -556,7 +556,7 @@ static int _map_single_page_2M(unsigned long *lv0_tbl, unsigned long va, { return MMU_MAP_ERROR_VANOTALIGN; } - if (pa & ARCH_SECTION_MASK) + if (pa & ARCH_PAGE_MASK) { return MMU_MAP_ERROR_PANOTALIGN; } @@ -803,8 +803,8 @@ void rt_hw_mem_setup_early(unsigned long *tbl0, unsigned long *tbl1, #ifdef RT_USING_SMART unsigned long va = KERNEL_VADDR_START; #else - extern unsigned char _start; - unsigned long va = (unsigned long) &_start; + extern unsigned char __start; + unsigned long va = (unsigned long) &__start; va = RT_ALIGN_DOWN(va, 0x200000); #endif @@ -826,3 +826,22 @@ void rt_hw_mem_setup_early(unsigned long *tbl0, unsigned long *tbl1, while (1); } } + +void *rt_hw_mmu_pgtbl_create(void) +{ + size_t *mmu_table; + mmu_table = (size_t *)rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); + if (!mmu_table) + { + return RT_NULL; + } + + memset(mmu_table, 0, ARCH_PAGE_SIZE); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); + return mmu_table; +} + +void rt_hw_mmu_pgtbl_delete(void *pgtbl) +{ + rt_pages_free(pgtbl, 0); +} diff --git a/libcpu/aarch64/common/mmu.h b/libcpu/aarch64/common/mmu.h index d85f79e792..875f925463 100644 --- a/libcpu/aarch64/common/mmu.h +++ b/libcpu/aarch64/common/mmu.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2006-2018, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-05-12 RT-Thread the first version + * 2023-08-15 Shell Support more mapping attribution */ #ifndef __MMU_H_ #define __MMU_H_ @@ -29,27 +30,42 @@ struct mem_desc struct rt_varea varea; }; +enum rt_hw_mmu_prot_t { + RT_HW_MMU_PROT_READ, + RT_HW_MMU_PROT_WRITE, + RT_HW_MMU_PROT_EXECUTE, + RT_HW_MMU_PROT_KERNEL, + RT_HW_MMU_PROT_USER, + RT_HW_MMU_PROT_CACHE, +}; + #define MMU_AF_SHIFT 10 #define MMU_SHARED_SHIFT 8 #define MMU_AP_SHIFT 6 #define MMU_MA_SHIFT 2 +#define MMU_AP_MASK (0x3 << MMU_AP_SHIFT) #define MMU_AP_KAUN 0UL /* kernel r/w, user none */ #define MMU_AP_KAUA 1UL /* kernel r/w, user r/w */ #define MMU_AP_KRUN 2UL /* kernel r, user none */ #define MMU_AP_KRUR 3UL /* kernel r, user r */ +#define MMU_ATTR_AF (1ul << MMU_AF_SHIFT) /* the access flag */ +#define MMU_ATTR_DBM (1ul << 51) /* the dirty bit modifier */ #define MMU_MAP_CUSTOM(ap, mtype) \ ((0x1UL << MMU_AF_SHIFT) | (0x2UL << MMU_SHARED_SHIFT) | \ ((ap) << MMU_AP_SHIFT) | ((mtype) << MMU_MA_SHIFT)) -#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM) -#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM) -#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM) -#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM) -#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM) -#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM) -#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM) -#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM) +#define MMU_MAP_K_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_MEM) +#define MMU_MAP_K_RO MMU_MAP_CUSTOM(MMU_AP_KRUN, NORMAL_NOCACHE_MEM) +#define MMU_MAP_K_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_MEM) +#define MMU_MAP_K_RW MMU_MAP_CUSTOM(MMU_AP_KAUN, NORMAL_NOCACHE_MEM) +#define MMU_MAP_K_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUN, DEVICE_MEM) +#define MMU_MAP_U_ROCB MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_MEM) +#define MMU_MAP_U_RO MMU_MAP_CUSTOM(MMU_AP_KRUR, NORMAL_NOCACHE_MEM) +#define MMU_MAP_U_RWCB MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_MEM) +#define MMU_MAP_U_RW MMU_MAP_CUSTOM(MMU_AP_KAUA, NORMAL_NOCACHE_MEM) +#define MMU_MAP_U_DEVICE MMU_MAP_CUSTOM(MMU_AP_KAUA, DEVICE_MEM) +#define MMU_MAP_TRACE(attr) ((attr) & ~(MMU_ATTR_AF | MMU_ATTR_DBM)) #define ARCH_SECTION_SHIFT 21 #define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT) @@ -88,7 +104,8 @@ void rt_hw_aspace_switch(struct rt_aspace *aspace); void *rt_hw_mmu_v2p(struct rt_aspace *aspace, void *vaddr); void rt_hw_mmu_kernel_map_init(struct rt_aspace *aspace, rt_size_t vaddr_start, rt_size_t size); -void rt_hw_mmu_ktbl_set(unsigned long tbl); +void *rt_hw_mmu_pgtbl_create(void); +void rt_hw_mmu_pgtbl_delete(void *pgtbl); static inline void *rt_hw_mmu_tbl_get() { @@ -101,8 +118,8 @@ static inline void *rt_hw_mmu_kernel_v2p(void *v_addr) { rt_ubase_t par; void *paddr; - asm volatile("at s1e1w, %0"::"r"(v_addr):"memory"); - asm volatile("mrs %0, par_el1":"=r"(par)::"memory"); + __asm__ volatile("at s1e1w, %0"::"r"(v_addr):"memory"); + __asm__ volatile("mrs %0, par_el1":"=r"(par)::"memory"); if (par & 0x1) { @@ -118,6 +135,73 @@ static inline void *rt_hw_mmu_kernel_v2p(void *v_addr) return paddr; } +/** + * @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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + attr = (attr & ~MMU_AP_MASK) | (MMU_AP_KAUA << MMU_AP_SHIFT); + break; + default: + RT_ASSERT(0); + } + return attr; +} + +/** + * @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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + if (attr & 0x40) + attr |= 0x80; + 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, enum rt_hw_mmu_prot_t prot) +{ + rt_bool_t rc; + switch (prot) + { + /* test write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + if ((attr & MMU_AP_MASK) == (MMU_AP_KAUA << MMU_AP_SHIFT)) + rc = RT_TRUE; + else + rc = RT_FALSE; + break; + default: + RT_ASSERT(0); + } + return rc; +} int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd); diff --git a/libcpu/aarch64/common/trap.c b/libcpu/aarch64/common/trap.c index 95adf628d8..487e940600 100644 --- a/libcpu/aarch64/common/trap.c +++ b/libcpu/aarch64/common/trap.c @@ -18,6 +18,10 @@ #include <backtrace.h> +#define DBG_TAG "libcpu.trap" +#define DBG_LVL DBG_LOG +#include <rtdbg.h> + void rt_unwind(struct rt_hw_exp_stack *regs, int pc_adj) { } @@ -40,7 +44,7 @@ static void _check_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *in if ((mode & 0x1f) == 0x00) { - rt_kprintf("%s! pc = 0x%08x\n", info, regs->pc - pc_adj); + rt_kprintf("%s! pc = 0x%x\n", info, regs->pc - pc_adj); /* user stack backtrace */ #ifdef RT_USING_LWP @@ -79,7 +83,7 @@ static void _check_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *in } } -int _get_type(unsigned long esr) +rt_inline int _get_type(unsigned long esr) { int ret; int fsc = esr & 0x3f; @@ -91,19 +95,31 @@ int _get_type(unsigned long esr) case 0x7: ret = MM_FAULT_TYPE_PAGE_FAULT; break; + case 0xc: + case 0xd: + case 0xe: + case 0xf: + ret = MM_FAULT_TYPE_ACCESS_FAULT; + break; + case 0x8: case 0x9: case 0xa: case 0xb: - ret = MM_FAULT_TYPE_ACCESS_FAULT; - break; + /* access flag fault */ default: ret = MM_FAULT_TYPE_GENERIC; } return ret; } -int check_user_stack(unsigned long esr, struct rt_hw_exp_stack *regs) +rt_inline long _irq_is_disable(long cpsr) { + return !!(cpsr & 0x80); +} + +static int user_fault_fixable(unsigned long esr, struct rt_hw_exp_stack *regs) +{ + rt_ubase_t level; unsigned char ec; void *dfar; int ret = 0; @@ -130,20 +146,24 @@ int check_user_stack(unsigned long esr, struct rt_hw_exp_stack *regs) break; } - if (fault_op) + /* page fault exception only allow from user space */ + lwp = lwp_self(); + if (lwp && fault_op) { - asm volatile("mrs %0, far_el1":"=r"(dfar)); + __asm__ volatile("mrs %0, far_el1":"=r"(dfar)); struct rt_aspace_fault_msg msg = { .fault_op = fault_op, .fault_type = fault_type, .fault_vaddr = dfar, }; - lwp = lwp_self(); - RT_ASSERT(lwp); + + lwp_user_setting_save(rt_thread_self()); + __asm__ volatile("mrs %0, daif\nmsr daifclr, 0x3\nisb\n":"=r"(level)); if (rt_aspace_fault_try_fix(lwp->aspace, &msg)) { ret = 1; } + __asm__ volatile("msr daif, %0\nisb\n"::"r"(level)); } return ret; } @@ -269,6 +289,12 @@ void rt_hw_trap_irq(void) #endif } +#ifdef RT_USING_SMART +#define DBG_CHECK_EVENT(regs, esr) dbg_check_event(regs, esr) +#else +#define DBG_CHECK_EVENT(regs, esr) (0) +#endif + void rt_hw_trap_fiq(void) { void *param; @@ -292,7 +318,7 @@ void rt_hw_trap_fiq(void) rt_hw_interrupt_ack(ir); } -void process_exception(unsigned long esr, unsigned long epc); +void print_exception(unsigned long esr, unsigned long epc); void SVC_Handler(struct rt_hw_exp_stack *regs); void rt_hw_trap_exception(struct rt_hw_exp_stack *regs) { @@ -302,27 +328,43 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs) asm volatile("mrs %0, esr_el1":"=r"(esr)); ec = (unsigned char)((esr >> 26) & 0x3fU); -#ifdef RT_USING_LWP - if (dbg_check_event(regs, esr)) + if (DBG_CHECK_EVENT(regs, esr)) { return; } - else -#endif - if (ec == 0x15) /* is 64bit syscall ? */ + else if (ec == 0x15) /* is 64bit syscall ? */ { SVC_Handler(regs); /* never return here */ } -#ifdef RT_USING_LWP - if (check_user_stack(esr, regs)) + +#ifdef RT_USING_SMART + /** + * Note: check_user_stack will take lock and it will possibly be a dead-lock + * if exception comes from kernel. + */ + if ((regs->cpsr & 0x1f) == 0) { - return; + if (user_fault_fixable(esr, regs)) + return; + } + else + { + if (_irq_is_disable(regs->cpsr)) + { + LOG_E("Kernel fault from interrupt/critical section"); + } + if (rt_critical_level() != 0) + { + LOG_E("scheduler is not available"); + } + else if (user_fault_fixable(esr, regs)) + return; } #endif - process_exception(esr, regs->pc); + print_exception(esr, regs->pc); rt_hw_show_register(regs); - rt_kprintf("current: %s\n", rt_thread_self()->parent.name); + LOG_E("current thread: %s\n", rt_thread_self()->parent.name); #ifdef RT_USING_FINSH list_thread(); diff --git a/libcpu/aarch64/cortex-a/entry_point.S b/libcpu/aarch64/cortex-a/entry_point.S index ee0ec86273..3c79fdebbc 100644 --- a/libcpu/aarch64/cortex-a/entry_point.S +++ b/libcpu/aarch64/cortex-a/entry_point.S @@ -38,8 +38,8 @@ boot_arg1 .req x23 boot_arg2 .req x24 stack_top .req x25 - .global _start -_start: +.global __start +__start: /* * Boot CPU general-purpose register settings: * x0 = physical address of device tree blob (dtb) in system RAM. @@ -165,8 +165,8 @@ _start: dsb sy #ifdef RT_USING_SMART - ldr x2, =_start - GET_PHY x3, _start + ldr x2, =__start + GET_PHY x3, __start sub x3, x3, x2 #else mov x3,0 diff --git a/libcpu/arm/cortex-a/mmu.c b/libcpu/arm/cortex-a/mmu.c index c573611616..0e1b50ab22 100644 --- a/libcpu/arm/cortex-a/mmu.c +++ b/libcpu/arm/cortex-a/mmu.c @@ -1,11 +1,12 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2012-01-10 bernard porting to AM1808 + * 2023-10-10 Shell Add permission control API */ #include <rthw.h> @@ -440,3 +441,25 @@ int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, { return -RT_ENOSYS; } + +#define KPTE_START (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT) + +void *rt_hw_mmu_pgtbl_create(void) +{ + size_t *mmu_table; + mmu_table = (size_t *)rt_pages_alloc_ext(2, PAGE_ANY_AVAILABLE); + if (!mmu_table) + { + return RT_NULL; + } + rt_memcpy(mmu_table + KPTE_START, (size_t *)rt_kernel_space.page_table + KPTE_START, ARCH_PAGE_SIZE); + rt_memset(mmu_table, 0, 3 * ARCH_PAGE_SIZE); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * ARCH_PAGE_SIZE); + + return mmu_table; +} + +void rt_hw_mmu_pgtbl_delete(void *pgtbl) +{ + rt_pages_free(pgtbl, 2); +} diff --git a/libcpu/arm/cortex-a/mmu.h b/libcpu/arm/cortex-a/mmu.h index 61b47a9402..bd016b835d 100644 --- a/libcpu/arm/cortex-a/mmu.h +++ b/libcpu/arm/cortex-a/mmu.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2006-2021, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-03-25 quanzhao the first version + * 2023-10-10 Shell Add permission control API */ #ifndef __MMU_H_ #define __MMU_H_ @@ -25,7 +26,7 @@ #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 */ @@ -65,14 +66,17 @@ struct mem_desc #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 MMU_MAP_K_ROCB ((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_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE)) +#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_ROCB ((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_B|MMU_MAP_MTBL_C|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 MMU_MAP_TRACE(attr) (attr) #define ARCH_SECTION_SHIFT 20 #define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT) @@ -97,6 +101,15 @@ struct mem_desc */ #define ARCH_MAP_FAILED ((void *)-1) +enum rt_hw_mmu_prot_t { + RT_HW_MMU_PROT_READ, + RT_HW_MMU_PROT_WRITE, + RT_HW_MMU_PROT_EXECUTE, + RT_HW_MMU_PROT_KERNEL, + RT_HW_MMU_PROT_USER, + RT_HW_MMU_PROT_CACHE, +}; + int rt_hw_mmu_ioremap_init(struct rt_aspace *aspace, void *v_address, size_t size); void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size); @@ -115,4 +128,90 @@ void *rt_hw_mmu_tbl_get(); int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd); +void *rt_hw_mmu_pgtbl_create(void); +void rt_hw_mmu_pgtbl_delete(void *pgtbl); + +#define AP_APX_MASK (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x3)) +#define AP_APX_URW_KRW (MMU_MAP_MTBL_AP2(0x0) | MMU_MAP_MTBL_AP01(0x3)) +#define AP_APX_URO_KRO (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x2)) + +/** + * @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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + if ((attr & AP_APX_MASK) == AP_APX_URW_KRW) + attr &= ~MMU_MAP_MTBL_AP01(0x1); + break; + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL: + switch (attr & AP_APX_MASK) + { + case MMU_MAP_MTBL_AP01(0): + break; + case MMU_MAP_MTBL_AP01(3): + attr = (attr & AP_APX_MASK) | AP_APX_URO_KRO; + default: + attr |= MMU_MAP_MTBL_AP2(0x1); + break; + } + 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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* add write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL: + attr |= MMU_MAP_MTBL_AP01(0x3); + attr &= ~MMU_MAP_MTBL_AP2(0x1); + 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, enum rt_hw_mmu_prot_t prot) +{ + rt_bool_t rc = 0; + switch (prot) + { + /* test write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + rc = (AP_APX_MASK & attr) == (AP_APX_URW_KRW); + break; + default: + RT_ASSERT(0); + } + return rc; +} + #endif diff --git a/libcpu/arm/cortex-a/trap.c b/libcpu/arm/cortex-a/trap.c index 800e145b64..f2d051f8a1 100644 --- a/libcpu/arm/cortex-a/trap.c +++ b/libcpu/arm/cortex-a/trap.c @@ -8,14 +8,16 @@ * 2013-07-20 Bernard first version */ -#include <backtrace.h> -#include <board.h> #include <rthw.h> #include <rtthread.h> +#include <board.h> +#include <backtrace.h> #include "interrupt.h" #include "mm_fault.h" +#include <rtdbg.h> + #ifdef RT_USING_FINSH extern long list_thread(void); #endif @@ -42,25 +44,47 @@ void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info) } } -int check_user_stack(struct rt_hw_exp_stack *regs) +int check_data_abort(struct rt_hw_exp_stack *regs) { + struct rt_lwp *lwp; void *dfar = RT_NULL; + rt_base_t dfsr = RT_NULL; + __asm__ volatile("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfar)); + __asm__ volatile("mrc p15, 0, %0, c5, c0, 0" : "=r"(dfsr)); + + struct rt_aspace_fault_msg msg = { + .fault_op = MM_FAULT_OP_WRITE, + .fault_type = MM_FAULT_TYPE_PAGE_FAULT, + .fault_vaddr = dfar, + }; + lwp = lwp_self(); + if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg)) + { + regs->pc -= 8; + return 1; + } + + return 0; +} + +int check_prefetch_abort(struct rt_hw_exp_stack *regs) +{ struct rt_lwp *lwp; - asm volatile("MRC p15, 0, %0, c6, c0, 0" : "=r"(dfar)); + void *ifar = RT_NULL; + rt_base_t ifsr = RT_NULL; + __asm__ volatile("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifar)); + __asm__ volatile("mrc p15, 0, %0, c5, c0, 1" : "=r"(ifsr)); - if ((dfar >= (void *)USER_STACK_VSTART) && (dfar < (void *)USER_STACK_VEND)) + struct rt_aspace_fault_msg msg = { + .fault_op = MM_FAULT_OP_READ, + .fault_type = MM_FAULT_TYPE_PAGE_FAULT, + .fault_vaddr = ifar, + }; + lwp = lwp_self(); + if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg)) { - struct rt_aspace_fault_msg msg = { - .fault_op = MM_FAULT_OP_WRITE, - .fault_type = MM_FAULT_TYPE_PAGE_FAULT, - .fault_vaddr = dfar, - }; - lwp = lwp_self(); - if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg)) - { - regs->pc -= 8; - return 1; - } + regs->pc -= 4; + return 1; } return 0; @@ -185,6 +209,10 @@ void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) { return; } + if (check_prefetch_abort(regs)) + { + return; + } check_user_fault(regs, 4, "User prefetch abort"); #endif rt_unwind(regs, 4); @@ -211,7 +239,7 @@ void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) { return; } - if (check_user_stack(regs)) + if (check_data_abort(regs)) { return; } diff --git a/libcpu/risc-v/t-head/c906/mmu.c b/libcpu/risc-v/t-head/c906/mmu.c index 75893d65e6..1754e5aaa4 100644 --- a/libcpu/risc-v/t-head/c906/mmu.c +++ b/libcpu/risc-v/t-head/c906/mmu.c @@ -7,6 +7,7 @@ * Date Author Notes * 2021-01-30 lizhirui first version * 2022-12-13 WangXiaoyao Port to new mm + * 2023-10-12 Shell Add permission control API */ #include <rtthread.h> @@ -567,3 +568,22 @@ void rt_hw_mmu_kernel_map_init(rt_aspace_t aspace, rt_size_t vaddr_start, rt_siz rt_hw_tlb_invalidate_all_local(); } + +void *rt_hw_mmu_pgtbl_create(void) +{ + size_t *mmu_table; + mmu_table = (rt_ubase_t *)rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); + if (!mmu_table) + { + return -RT_ENOMEM; + } + rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); + + return mmu_table; +} + +void rt_hw_mmu_pgtbl_delete(void *pgtbl) +{ + rt_pages_free(pgtbl, 0); +} diff --git a/libcpu/risc-v/t-head/c906/mmu.h b/libcpu/risc-v/t-head/c906/mmu.h index 809e514b82..58229464cd 100644 --- a/libcpu/risc-v/t-head/c906/mmu.h +++ b/libcpu/risc-v/t-head/c906/mmu.h @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2021-01-30 lizhirui first version + * 2023-10-12 Shell Add permission control API */ #ifndef __MMU_H__ @@ -70,4 +71,7 @@ void *rt_hw_mmu_v2p(rt_aspace_t aspace, void *vaddr); int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd); +void *rt_hw_mmu_pgtbl_create(void); +void rt_hw_mmu_pgtbl_delete(void *pgtbl); + #endif diff --git a/libcpu/risc-v/t-head/c906/riscv_mmu.h b/libcpu/risc-v/t-head/c906/riscv_mmu.h index 87db683b05..dfb5a8ee48 100644 --- a/libcpu/risc-v/t-head/c906/riscv_mmu.h +++ b/libcpu/risc-v/t-head/c906/riscv_mmu.h @@ -7,6 +7,7 @@ * Date Author Notes * 2021-01-30 lizhirui first version * 2021-05-03 lizhirui porting to c906 + * 2023-10-12 Shell Add permission control API */ #ifndef __RISCV_MMU_H__ @@ -90,8 +91,10 @@ #define MMU_MAP_K_RWCB PTE_WRAP(PAGE_ATTR_CB | PTE_G | PAGE_ATTR_RWX | PTE_V) #define MMU_MAP_K_RW PTE_WRAP(PTE_G | PAGE_ATTR_RWX | PTE_V) #define MMU_MAP_U_RWCB PTE_WRAP(PAGE_ATTR_CB | PTE_U | PAGE_ATTR_RWX | PTE_V) +#define MMU_MAP_U_ROCB PTE_WRAP(PAGE_ATTR_CB | PTE_U | PAGE_ATTR_READONLY | PTE_V) #define MMU_MAP_U_RWCB_XN PTE_WRAP(PAGE_ATTR_CB | PTE_U | PAGE_ATTR_XN | PTE_V) #define MMU_MAP_U_RW PTE_WRAP(PTE_U | PAGE_ATTR_RWX | PTE_V) +#define MMU_MAP_TRACE(attr) (attr) #define PTE_XWR_MASK 0xe @@ -108,4 +111,71 @@ void mmu_set_pagetable(rt_ubase_t addr); void mmu_enable_user_page_access(); void mmu_disable_user_page_access(); +enum rt_hw_mmu_prot_t { + RT_HW_MMU_PROT_READ, + RT_HW_MMU_PROT_WRITE, + RT_HW_MMU_PROT_EXECUTE, + RT_HW_MMU_PROT_KERNEL, + RT_HW_MMU_PROT_USER, + RT_HW_MMU_PROT_CACHE, +}; + +/** + * @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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + 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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* add write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + 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, enum rt_hw_mmu_prot_t prot) +{ + rt_bool_t rc = 0; + switch (prot) + { + /* test write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + default: + RT_ASSERT(0); + } + return rc; +} + #endif diff --git a/libcpu/risc-v/virt64/mmu.c b/libcpu/risc-v/virt64/mmu.c index 091be5adab..c1a62bfdea 100644 --- a/libcpu/risc-v/virt64/mmu.c +++ b/libcpu/risc-v/virt64/mmu.c @@ -7,6 +7,7 @@ * Date Author Notes * 2021-01-30 lizhirui first version * 2022-12-13 WangXiaoyao Port to new mm + * 2023-10-12 Shell Add permission control API */ #include <rtthread.h> @@ -490,3 +491,22 @@ void rt_hw_mmu_setup(rt_aspace_t aspace, struct mem_desc *mdesc, int desc_nr) rt_hw_aspace_switch(&rt_kernel_space); rt_page_cleanup(); } + +void *rt_hw_mmu_pgtbl_create(void) +{ + size_t *mmu_table; + mmu_table = (rt_ubase_t *)rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); + if (!mmu_table) + { + return RT_NULL; + } + rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); + + return mmu_table; +} + +void rt_hw_mmu_pgtbl_delete(void *pgtbl) +{ + rt_pages_free(pgtbl, 0); +} diff --git a/libcpu/risc-v/virt64/mmu.h b/libcpu/risc-v/virt64/mmu.h index 809e514b82..58229464cd 100644 --- a/libcpu/risc-v/virt64/mmu.h +++ b/libcpu/risc-v/virt64/mmu.h @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2021-01-30 lizhirui first version + * 2023-10-12 Shell Add permission control API */ #ifndef __MMU_H__ @@ -70,4 +71,7 @@ void *rt_hw_mmu_v2p(rt_aspace_t aspace, void *vaddr); int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd); +void *rt_hw_mmu_pgtbl_create(void); +void rt_hw_mmu_pgtbl_delete(void *pgtbl); + #endif diff --git a/libcpu/risc-v/virt64/riscv_mmu.h b/libcpu/risc-v/virt64/riscv_mmu.h index 2e255263f5..a56492dcab 100644 --- a/libcpu/risc-v/virt64/riscv_mmu.h +++ b/libcpu/risc-v/virt64/riscv_mmu.h @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2021-01-30 lizhirui first version + * 2023-10-12 Shell Add permission control API */ #ifndef __RISCV_MMU_H__ @@ -93,4 +94,74 @@ void mmu_set_pagetable(rt_ubase_t addr); void mmu_enable_user_page_access(); void mmu_disable_user_page_access(); +enum rt_hw_mmu_prot_t { + RT_HW_MMU_PROT_READ, + RT_HW_MMU_PROT_WRITE, + RT_HW_MMU_PROT_EXECUTE, + RT_HW_MMU_PROT_KERNEL, + RT_HW_MMU_PROT_USER, + RT_HW_MMU_PROT_CACHE, +}; + +/** + * @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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* remove write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + attr &= ~PTE_W; + 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, enum rt_hw_mmu_prot_t prot) +{ + switch (prot) + { + /* add write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + attr |= PTE_W; + 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, enum rt_hw_mmu_prot_t prot) +{ + rt_bool_t rc = 0; + switch (prot) + { + /* test write permission for user */ + case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER: + rc = !!(attr & PTE_W); + default: + RT_ASSERT(0); + } + return rc; +} + #endif |
