diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 0d417895c6e..72bc2b2f787 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -96,6 +96,8 @@ config ARCH_CHIP_MPFS select ARCH_HAVE_FPU select ARCH_HAVE_DPFPU select ARCH_HAVE_MPU + select ARCH_HAVE_MMU + select ARCH_MMU_TYPE_SV39 select ARCH_HAVE_RESET select ARCH_HAVE_SPI_CS_CONTROL select ARCH_HAVE_PWM_MULTICHAN @@ -182,6 +184,10 @@ config ARCH_RISCV_INTXCPT_EXTREGS endif +config ARCH_MMU_TYPE_SV39 + bool + default n + source "arch/risc-v/src/opensbi/Kconfig" source "arch/risc-v/src/common/Kconfig" diff --git a/arch/risc-v/src/common/riscv_mmu.c b/arch/risc-v/src/common/riscv_mmu.c new file mode 100644 index 00000000000..d2d88ed18e5 --- /dev/null +++ b/arch/risc-v/src/common/riscv_mmu.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/risc-v/src/common/riscv_mmu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "riscv_internal.h" +#include "riscv_mmu.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void mmu_ln_setentry(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr, + uintptr_t vaddr, uint32_t mmuflags) +{ + uintptr_t *lntable = (uintptr_t *)lnvaddr; + uint32_t index; + + DEBUGASSERT(ptlevel <= RV_MMU_PT_LEVELS); + + /* Test if this is a leaf PTE, if it is, set A+D even if they are not used + * by the implementation. + * + * If not, clear A+D+U because the spec. says: + * For non-leaf PTEs, the D, A, and U bits are reserved for future use and + * must be cleared by software for forward compatibility. + */ + + if (mmuflags & PTE_LEAF_MASK) + { + mmuflags |= (PTE_A | PTE_D); + } + else + { + mmuflags &= ~(PTE_A | PTE_D | PTE_U); + } + + /* Make sure the entry is valid */ + + mmuflags |= PTE_VALID; + + /* Calculate index for lntable */ + + index = (vaddr >> RV_MMU_VADDR_SHIFT(ptlevel)) & RV_MMU_VPN_MASK; + + /* Move PPN to correct position */ + + paddr >>= RV_MMU_PTE_PPN_SHIFT; + + /* Save it */ + + lntable[index] = (paddr | mmuflags); + + /* Update with memory by flushing the cache(s) */ + + mmu_invalidate_tlb_by_vaddr(vaddr); +} + +void mmu_ln_map_region(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr, + uintptr_t vaddr, size_t size, uint32_t mmuflags) +{ + uintptr_t end_paddr = paddr + size; + + while (paddr < end_paddr) + { + mmu_ln_setentry(ptlevel, lnvaddr, paddr, vaddr, mmuflags); + paddr += RV_MMU_PAGE_SIZE; + vaddr += RV_MMU_PAGE_SIZE; + } +} diff --git a/arch/risc-v/src/common/riscv_mmu.h b/arch/risc-v/src/common/riscv_mmu.h new file mode 100644 index 00000000000..ec0b22875c4 --- /dev/null +++ b/arch/risc-v/src/common/riscv_mmu.h @@ -0,0 +1,206 @@ +/**************************************************************************** + * arch/risc-v/src/common/riscv_mmu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef ___ARCH_RISC_V_SRC_COMMON_RISCV_MMU_H_ +#define ___ARCH_RISC_V_SRC_COMMON_RISCV_MMU_H_ + +/* RV32/64 page size */ + +#define RV_MMU_PAGE_SHIFT (12) +#define RV_MMU_PAGE_SIZE (1 << RV_MMU_PAGE_SHIFT) /* 4K pages */ + +/* Supervisor Address Translation and Protection (satp) */ + +#define SATP_PPN_SHIFT (0) +#define SATP_PPN_MASK (((1ul << 44) - 1) << SATP_PPN_SHIFT) +#define SATP_ASID_SHIFT (44) +#define SATP_ASID_MASK (((1ul << 16) - 1) << SATP_ASID_SHIFT) +#define SATP_MODE_SHIFT (60) +#define SATP_MODE_MASK (((1ul << 4) - 1) << SATP_MODE_SHIFT) + +/* Modes, for RV32 only 1 is valid, for RV64 1-7 and 10-15 are reserved */ + +#define SATP_MODE_BARE (0ul) +#define SATP_MODE_SV32 (1ul) +#define SATP_MODE_SV39 (8ul) +#define SATP_MODE_SV48 (9ul) + +/* satp address to PPN translation */ + +#define SATP_ADDR_TO_PPN(_addr) ((_addr) >> RV_MMU_PAGE_SHIFT) + +/* Common Page Table Entry (PTE) bits */ + +#define PTE_VALID (1 << 0) /* PTE is valid */ +#define PTE_R (1 << 1) /* Page is readable */ +#define PTE_W (1 << 2) /* Page is writable */ +#define PTE_X (1 << 3) /* Page is executable */ +#define PTE_U (1 << 4) /* Page is a user mode page */ +#define PTE_G (1 << 5) /* Page is a global mapping */ +#define PTE_A (1 << 6) /* Page has been accessed */ +#define PTE_D (1 << 7) /* Page is dirty */ + +/* Check if leaf PTE entry or not (if X/W/R are set it is) */ + +#define PTE_LEAF_MASK (7 << 1) + +/* SvX definitions, only Sv39 is currently supported, but it should be + * trivial to extend the driver to support other SvX implementations + * + * Sv39 has: + * - 4K page size + * - 3 page table levels + * - 9-bit VPN width + */ + +#ifdef CONFIG_ARCH_MMU_TYPE_SV39 +#define RV_MMU_PTE_PPN_SHIFT (2) +#define RV_MMU_VPN_WIDTH (9) +#define RV_MMU_VPN_MASK ((1 << RV_MMU_VPN_WIDTH) - 1) +#define RV_MMU_PT_LEVELS (3) +#define RV_MMU_VADDR_SHIFT(_n) (RV_MMU_PAGE_SHIFT + RV_MMU_VPN_WIDTH * \ + (RV_MMU_PT_LEVELS - (_n))) +#define RV_MMU_SATP_MODE SATP_MODE_SV39 +#else +#error "Unsupported RISC-V MMU implementation selected" +#endif /* CONFIG_ARCH_MMU_TYPE_SV39 */ + +/**************************************************************************** + * Name: mmu_enable + * + * Description: + * Enable MMU and set the base page table address + * + * Input Parameters: + * pgbase - The physical base address of the translation table base + * asid - Address space identifier. This can be used to identify different + * address spaces. It is not necessary to use this, nor is it necessary + * for the RISC-V implementation to implement such bits. This means in + * practice that the value should not be used in this generic driver. + * + ****************************************************************************/ + +static inline void mmu_enable(uintptr_t pgbase, uint16_t asid) +{ + uintptr_t reg; + reg = ((RV_MMU_SATP_MODE << SATP_MODE_SHIFT) & SATP_MODE_MASK); + reg |= (((uintptr_t)asid << SATP_ASID_SHIFT) & SATP_ASID_MASK); + reg |= ((SATP_ADDR_TO_PPN(pgbase) << SATP_PPN_SHIFT) & SATP_PPN_MASK); + + /* Commit to satp and synchronize */ + + __asm__ __volatile__ + ( + "csrw satp, %0\n" + "sfence.vma x0, x0\n" + "fence iorw, iorw\n" + : + : "rK" (reg) + : "memory" + ); +} + +/**************************************************************************** + * Name: mmu_invalidate_tlb_by_vaddr + * + * Description: + * Flush the TLB for vaddr entry + * + * Input Parameters: + * vaddr - The virtual address to flush + * + ****************************************************************************/ + +static inline void mmu_invalidate_tlb_by_vaddr(uintptr_t vaddr) +{ + __asm__ __volatile__ + ( + "sfence.vma x0, %0\n" + : + : "rK" (vaddr) + : "memory" + ); +} + +/**************************************************************************** + * Name: mmu_invalidate_tlbs + * + * Description: + * Flush the entire TLB + * + ****************************************************************************/ + +static inline void mmu_invalidate_tlbs(void) +{ + __asm__ __volatile__ + ( + "sfence.vma x0, x0\n" + : + : + : "memory" + ); +} + +/**************************************************************************** + * Name: mmu_ln_setentry + * + * Description: + * Set a level n translation table entry. + * + * Input Parameters: + * ptlevel - The translation table level, amount of levels is + * MMU implementation specific + * lnvaddr - The virtual address of the beginning of the page table at + * level n + * paddr - The physical address to be mapped. Must be aligned to a PPN + * address boundary which is dependent on the level of the entry + * vaddr - Must be aligned to a PPN + * address boundary which is dependent on the level of the entry + * mmuflags - The MMU flags to use in the mapping. + * + ****************************************************************************/ + +void mmu_ln_setentry(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr, + uintptr_t vaddr, uint32_t mmuflags); + +/**************************************************************************** + * Name: mmu_ln_map_region + * + * Description: + * Set a translation table region for level n + * + * Input Parameters: + * ptlevel - The translation table level, amount of levels is + * MMU implementation specific + * lnvaddr - The virtual address of the beginning of the page table at + * level n + * paddr - The physical address to be mapped. Must be aligned to a PPN + * address boundary which is dependent on the level of the entry + * vaddr - Must be aligned to a PPN + * address boundary which is dependent on the level of the entry + * size - The size of the region in bytes + * mmuflags - The MMU flags to use in the mapping. + * + ****************************************************************************/ + +void mmu_ln_map_region(uint32_t ptlevel, uintptr_t lnvaddr, uintptr_t paddr, + uintptr_t vaddr, size_t size, uint32_t mmuflags); + +#endif /* ___ARCH_RISC_V_SRC_COMMON_RISCV_MMU_H_ */ diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index f20d1ae628c..d9e5ea36232 100755 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -60,13 +60,23 @@ CHIP_CSRCS += mpfs_dma.c endif ifeq ($(CONFIG_BUILD_PROTECTED),y) -CMN_CSRCS += riscv_task_start.c riscv_pthread_start.c -CMN_CSRCS += riscv_signal_dispatch.c riscv_pmp.c +CMN_CSRCS += riscv_task_start.c +CMN_CSRCS += riscv_pthread_start.c riscv_pthread_exit.c +CMN_CSRCS += riscv_signal_dispatch.c + CMN_UASRCS += riscv_signal_handler.S CHIP_CSRCS += mpfs_userspace.c endif +ifeq ($(CONFIG_ARCH_USE_MPU),y) +CMN_CSRCS += riscv_pmp.c +endif + +ifeq ($(CONFIG_ARCH_USE_MMU),y) +CMN_CSRCS += riscv_mmu.c +endif + ifeq ($(CONFIG_SPI),y) CHIP_CSRCS += mpfs_spi.c endif diff --git a/arch/risc-v/src/mpfs/mpfs_head.S b/arch/risc-v/src/mpfs/mpfs_head.S index 39d75808bb3..5ab06fba076 100755 --- a/arch/risc-v/src/mpfs/mpfs_head.S +++ b/arch/risc-v/src/mpfs/mpfs_head.S @@ -108,6 +108,11 @@ __start: csrw mideleg, 0 csrw medeleg, 0 + /* Disable MMU if not done already */ + + csrw satp, zero + fence + /* invalid all MMU TLB Entry */ sfence.vma x0, x0