This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 81188d9c942d238129c8f58355259e4767322514
Author: Ville Juven <[email protected]>
AuthorDate: Mon Jan 24 10:17:08 2022 +0200

    Extend the RISC-V PMP functionality
    
    - Add test for mode support, which is architecture dependent
    - Add tests for address alignment and region size
    - Add option to query for access rights
     - The function goes through every PMP entry and tests if an address
       range from [base, base+size] has been configured for desired
       access rights.
     - If several PMP entries match the range and access rights, the
       information is combined
     - End result is either no access, a partial match was found, or a full
       match was found. Details about the partial match are not provided.
    
    The intent for testing access rights and not just blindly applying them
    is a case where they are already set in e.g. a bootloader. In this
    case, nothing should be done, unless the configuration does not match,
    in which case the software must not continue further.
---
 arch/risc-v/Kconfig                     |  24 ++
 arch/risc-v/include/csr.h               |   1 +
 arch/risc-v/src/common/riscv_internal.h |  14 +-
 arch/risc-v/src/common/riscv_pmp.c      | 562 +++++++++++++++++++++++++++++++-
 arch/risc-v/src/mpfs/Kconfig            |  14 +
 arch/risc-v/src/mpfs/mpfs_userspace.c   |  80 +++--
 6 files changed, 666 insertions(+), 29 deletions(-)

diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig
index 72bc2b2..4fac78e 100644
--- a/arch/risc-v/Kconfig
+++ b/arch/risc-v/Kconfig
@@ -101,6 +101,7 @@ config ARCH_CHIP_MPFS
        select ARCH_HAVE_RESET
        select ARCH_HAVE_SPI_CS_CONTROL
        select ARCH_HAVE_PWM_MULTICHAN
+       select PMP_HAS_LIMITED_FEATURES
        ---help---
                MicroChip Polarfire processor (RISC-V 64bit core with GCVX 
extensions).
 
@@ -188,6 +189,29 @@ config ARCH_MMU_TYPE_SV39
        bool
        default n
 
+# MPU has certain architecture dependent configurations, which are presented
+# here. Default is that the full RISC-V PMP specification is supported.
+
+config PMP_HAS_LIMITED_FEATURES
+       bool
+       default n
+
+config ARCH_MPU_MIN_BLOCK_SIZE
+       int "Minimum MPU (PMP) block size"
+       default 4       if !PMP_HAS_LIMITED_FEATURES
+
+config ARCH_MPU_HAS_TOR
+       bool "PMP supports TOR"
+       default y       if !PMP_HAS_LIMITED_FEATURES
+
+config ARCH_MPU_HAS_NO4
+       bool "PMP supports NO4"
+       default y       if !PMP_HAS_LIMITED_FEATURES
+
+config ARCH_MPU_HAS_NAPOT
+       bool "PMP supports NAPOT"
+       default y       if !PMP_HAS_LIMITED_FEATURES
+
 source "arch/risc-v/src/opensbi/Kconfig"
 source "arch/risc-v/src/common/Kconfig"
 
diff --git a/arch/risc-v/include/csr.h b/arch/risc-v/include/csr.h
index 5d023ed..d1c1c70 100644
--- a/arch/risc-v/include/csr.h
+++ b/arch/risc-v/include/csr.h
@@ -346,6 +346,7 @@
 #define PMPCFG_R        (1 << 0)  /* readable ? */
 #define PMPCFG_W        (1 << 1)  /* writeable ? */
 #define PMPCFG_X        (1 << 2)  /* excutable ? */
+#define PMPCFG_RWX_MASK (7 << 0)  /* access rights mask */
 #define PMPCFG_A_OFF    (0 << 3)  /* null region (disabled) */
 #define PMPCFG_A_TOR    (1 << 3)  /* top of range */
 #define PMPCFG_A_NA4    (2 << 3)  /* naturally aligned four-byte region */
diff --git a/arch/risc-v/src/common/riscv_internal.h 
b/arch/risc-v/src/common/riscv_internal.h
index 87c4158..596dcae 100644
--- a/arch/risc-v/src/common/riscv_internal.h
+++ b/arch/risc-v/src/common/riscv_internal.h
@@ -91,6 +91,12 @@
 #  endif
 #endif
 
+/* Return values from riscv_check_pmp_access */
+
+#define PMP_ACCESS_OFF      (0)     /* Access for area not set */
+#define PMP_ACCESS_DENIED   (-1)    /* Access set and denied */
+#define PMP_ACCESS_FULL     (1)     /* Access set and allowed */
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -177,8 +183,12 @@ void riscv_restorefpu(const uintptr_t *regs);
 
 /* RISC-V PMP Config ********************************************************/
 
-void riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
-                             uintptr_t base, uintptr_t size);
+int riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
+                            uintptr_t base, uintptr_t size);
+
+int riscv_check_pmp_access(uintptr_t attr, uintptr_t base, uintptr_t size);
+int riscv_configured_pmp_regions(void);
+int riscv_next_free_pmp_region(void);
 
 /* Power management *********************************************************/
 
diff --git a/arch/risc-v/src/common/riscv_pmp.c 
b/arch/risc-v/src/common/riscv_pmp.c
index 1fa0daf..b746e7f 100644
--- a/arch/risc-v/src/common/riscv_pmp.c
+++ b/arch/risc-v/src/common/riscv_pmp.c
@@ -22,6 +22,9 @@
  * Included Files
  ****************************************************************************/
 
+#include <stdbool.h>
+
+#include <nuttx/compiler.h>
 #include <nuttx/config.h>
 #include <nuttx/arch.h>
 #include <arch/csr.h>
@@ -32,6 +35,18 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* Minimum supported block size */
+
+#if !defined CONFIG_ARCH_MPU_MIN_BLOCK_SIZE
+#define MIN_BLOCK_SIZE          (__riscv_xlen / 8)
+#else
+#define MIN_BLOCK_SIZE          CONFIG_ARCH_MPU_MIN_BLOCK_SIZE
+#endif
+
+/* Address and block size alignment mask */
+
+#define BLOCK_ALIGN_MASK        (MIN_BLOCK_SIZE - 1)
+
 #define PMP_CFG_BITS_CNT        (8)
 #define PMP_CFG_FLAG_MASK       (0xFF)
 
@@ -44,6 +59,361 @@
       reg |= attr << (offset * PMP_CFG_BITS_CNT); \
     } while(0);
 
+#define PMP_READ_REGION_FROM_REG(region, reg) \
+  ({ \
+    uintptr_t tmp = READ_CSR(reg); \
+    tmp >>= ((region % PMP_CFG_CNT_IN_REG) * PMP_CFG_BITS_CNT); \
+    tmp &= PMP_CFG_FLAG_MASK; \
+    tmp; \
+  })
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Helper structure for handling a PMP entry */
+
+struct pmp_entry_s
+{
+  uintptr_t base;   /* Base address of region */
+  uintptr_t end;    /* End address of region */
+  uintptr_t size;   /* Region size */
+  uint8_t   mode;   /* Address matching mode */
+  uint8_t   rwx;    /* Access rights */
+};
+
+typedef struct pmp_entry_s pmp_entry_t;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pmp_check_addrmatch_type
+ *
+ * Description:
+ *   Test if an address matching type is supported by the architecture.
+ *
+ * Input Parameters:
+ *   type - The type to test.
+ *
+ * Returned Value:
+ *   true if it is, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool pmp_check_addrmatch_type(uintptr_t type)
+{
+  /* Parameter is potentially unused */
+
+  UNUSED(type);
+#ifdef CONFIG_ARCH_MPU_HAS_TOR
+  if (type == PMPCFG_A_TOR)
+    {
+      return true;
+    }
+
+#endif
+#ifdef CONFIG_ARCH_MPU_HAS_NO4
+  if (type == PMPCFG_A_NA4)
+    {
+      return true;
+    }
+
+#endif
+#ifdef CONFIG_ARCH_MPU_HAS_NAPOT
+  if (type == PMPCFG_A_NAPOT)
+    {
+      return true;
+    }
+#endif
+
+  /* None of the supported types match */
+
+  return false;
+}
+
+/****************************************************************************
+ * Name: pmp_check_region_attrs
+ *
+ * Description:
+ *   Test if the base address and size of region meet alignment requirements.
+ *
+ * Input Parameters:
+ *   base - The base address of the region.
+ *   size - The memory length of the region.
+ *
+ * Returned Value:
+ *   true if it is, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size)
+{
+  /* Check that the size is not too small */
+
+  if (size < MIN_BLOCK_SIZE)
+    {
+      return false;
+    }
+
+  /* Check that the base address is aligned properly */
+
+  if ((base & BLOCK_ALIGN_MASK) != 0)
+    {
+      return false;
+    }
+
+  /* Check that the size is aligned properly */
+
+  if ((size & BLOCK_ALIGN_MASK) != 0)
+    {
+      return false;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pmp_read_region_cfg
+ *
+ * Description:
+ *   Read PMP configuration for region
+ *
+ * Input Parameters:
+ *   region - Region number.
+ *
+ * Returned Value:
+ *   Configuration value from pmpcfg+region
+ *
+ ****************************************************************************/
+
+static uintptr_t pmp_read_region_cfg(uintptr_t region)
+{
+# if (__riscv_xlen == 32)
+  switch (region)
+    {
+      case 0 ... 3:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg0);
+
+      case 4 ... 7:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg1);
+
+      case 8 ... 11:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg2);
+
+      case 12 ... 15:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg3);
+
+      default:
+        break;
+    }
+# elif (__riscv_xlen == 64)
+  switch (region)
+    {
+      case 0 ... 7:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg0);
+
+      case 8 ... 15:
+        return PMP_READ_REGION_FROM_REG(region, pmpcfg2);
+
+      default:
+        break;
+    }
+#endif
+
+  /* Never executed */
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: pmp_read_addr
+ *
+ * Description:
+ *   Read address for region
+ *
+ * Input Parameters:
+ *   region - Region number.
+ *
+ * Returned Value:
+ *   Address value from pmpcfg+region
+ *
+ ****************************************************************************/
+
+static uintptr_t pmp_read_addr(uintptr_t region)
+{
+  switch (region)
+      {
+        case 0:
+          return READ_CSR(pmpaddr0);
+
+        case 1:
+          return READ_CSR(pmpaddr1);
+
+        case 2:
+          return READ_CSR(pmpaddr2);
+
+        case 3:
+          return READ_CSR(pmpaddr3);
+
+        case 4:
+          return READ_CSR(pmpaddr4);
+
+        case 5:
+          return READ_CSR(pmpaddr5);
+
+        case 6:
+          return READ_CSR(pmpaddr6);
+
+        case 7:
+          return READ_CSR(pmpaddr7);
+
+        case 8:
+          return READ_CSR(pmpaddr8);
+
+        case 9:
+          return READ_CSR(pmpaddr9);
+
+        case 10:
+          return READ_CSR(pmpaddr10);
+
+        case 11:
+          return READ_CSR(pmpaddr11);
+
+        case 12:
+          return READ_CSR(pmpaddr12);
+
+        case 13:
+          return READ_CSR(pmpaddr13);
+
+        case 14:
+          return READ_CSR(pmpaddr14);
+
+        case 15:
+          return READ_CSR(pmpaddr15);
+
+        default:
+          break;
+      }
+
+  /* Never executed */
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: pmp_napot_decode
+ *
+ * Description:
+ *   Decode base and size from NAPOT value
+ *
+ * Input Parameters:
+ *   val  - Value to decode.
+ *   base - Base out.
+ *   size - Size out.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void pmp_napot_decode(uintptr_t val, uintptr_t * base,
+                             uintptr_t * size)
+{
+  uint64_t mask = (uint64_t)(-1) >> 1;
+  uint64_t pot  = __riscv_xlen + 2;
+
+  while (mask)
+    {
+      if ((val & mask) == mask)
+        {
+          break;
+        }
+
+      pot--;
+      mask >>= 1;
+    }
+
+  val &= ~mask;
+  *base = (val << 2);
+  *size = (1 << pot);
+}
+
+/****************************************************************************
+ * Name: pmp_read
+ *
+ * Description:
+ *   Read PMP region into PMP entry
+ *
+ * Input Parameters:
+ *   region - Region number.
+ *   entry  - Entry out
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void pmp_read(uintptr_t region, pmp_entry_t * entry)
+{
+  uintptr_t addr = 0;
+  uintptr_t size = 0;
+  uintptr_t mode = 0;
+  uintptr_t rwx  = 0;
+  uintptr_t cfg  = 0;
+
+  addr = pmp_read_addr(region);
+  cfg  = pmp_read_region_cfg(region);
+  mode = cfg & PMPCFG_A_MASK;
+  rwx  = cfg & PMPCFG_RWX_MASK;
+
+  switch (mode)
+  {
+    case PMPCFG_A_TOR:
+      addr <<= 2;
+
+      /* TOR region, must peek into prior region for size */
+
+      if (region == 0)
+        {
+          size = addr;
+        }
+      else
+        {
+          size = addr - pmp_read_addr(region - 1);
+        }
+
+      break;
+
+    case PMPCFG_A_NA4:
+      addr <<= 2;
+      size = 4;
+      break;
+
+    case PMPCFG_A_NAPOT:
+      pmp_napot_decode(addr, &addr, &size);
+      break;
+
+    default:
+      break;
+  }
+
+  entry->base = addr;
+  entry->end  = addr + size;
+  entry->size = size;
+  entry->rwx  = rwx;
+  entry->mode = mode;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -63,17 +433,32 @@
  *   and the size must be power-of-two according to the the PMP spec.
  *
  * Returned Value:
- *   None.
+ *   0 on succeess; negated error on failure
  *
  ****************************************************************************/
 
-void riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
-                             uintptr_t base, uintptr_t size)
+int riscv_config_pmp_region(uintptr_t region, uintptr_t attr,
+                            uintptr_t base, uintptr_t size)
 {
-  uintptr_t addr = 0;
-  uintptr_t cfg = 0;
+  uintptr_t addr    = 0;
+  uintptr_t cfg     = 0;
+  uintptr_t type    = (attr & PMPCFG_A_MASK);
+
+  /* Check that the architecture supports address matching type */
+
+  if (pmp_check_addrmatch_type(type) == false)
+    {
+      return -EINVAL;
+    }
+
+  /* Check the region attributes */
+
+  if (pmp_check_region_attrs(base, size))
+    {
+      return -EINVAL;
+    }
 
-  /* TODO: check the base address alignment and size */
+  /* Calculate new base address from type */
 
   addr = base >> 2;
   if (PMPCFG_A_NAPOT == (attr & PMPCFG_A_MASK))
@@ -81,6 +466,8 @@ void riscv_config_pmp_region(uintptr_t region, uintptr_t 
attr,
       addr |= (size - 1) >> 3;
     }
 
+  /* Set the address value */
+
   switch (region)
     {
       case 0:
@@ -151,6 +538,8 @@ void riscv_config_pmp_region(uintptr_t region, uintptr_t 
attr,
         break;
     }
 
+  /* Set the configuration register value */
+
 # if (__riscv_xlen == 32)
   switch (region)
     {
@@ -206,4 +595,165 @@ void riscv_config_pmp_region(uintptr_t region, uintptr_t 
attr,
   /* fence is needed when page-based virtual memory is implemented */
 
   __asm volatile("sfence.vma x0, x0" : : : "memory");
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: riscv_check_pmp_access
+ *
+ * Description:
+ *   This function will set the specific PMP region with the desired cfg.
+ *
+ * Input Parameters:
+ *   attr - The region configurations.
+ *   base - The base address of the region.
+ *   size - The memory length of the region.
+ *   For the NAPOT mode, the base address must aligned to the size boundary,
+ *   and the size must be power-of-two according to the the PMP spec.
+ *
+ * Returned Value:
+ *   0 if access rights are not set at all
+ *   < 0 if access rights are set and match match partially
+ *   > 0 if access rights are set and match fully
+ *
+ ****************************************************************************/
+
+int riscv_check_pmp_access(uintptr_t attr, uintptr_t base, uintptr_t size)
+{
+  pmp_entry_t   entry;
+  uintptr_t     end;
+  uintptr_t     orgsize;
+  unsigned int  region;
+
+  /* Go through every single configured region and test the attributes */
+
+  attr    = (attr & PMPCFG_RWX_MASK);
+  end     = base + size;
+  orgsize = size;
+
+  for (region = 0; region < 16 && size > 0; region++)
+    {
+      /* Find matching configuration first */
+
+      pmp_read(region, &entry);
+
+      /* Check if any configuration at all */
+
+      if (entry.mode == PMPCFG_A_OFF)
+        {
+          continue;
+        }
+
+      /* Does this address range match ? Take partial matches into account.
+       *
+       * There are four possibilities:
+       * 1: Full match; region inside mapped area
+       * 2: Partial match; mapped area inside region
+       * 3: Partial match; base inside mapped region, end outside
+       * 4: Partial match; base outside mapped region, end inside
+       */
+
+      if ((base >= entry.base && end  <= entry.end) ||
+          (base <= entry.base && end  >= entry.end) ||
+          (base >= entry.base && base <= entry.end) ||
+          (end  >= entry.base && end  <= entry.end))
+        {
+          /* Found a matching splice, check rights */
+
+          if ((entry.rwx & attr) == attr)
+            {
+              /* Found matching region that allows access */
+
+              size -= min(end, entry.end) - max(base, entry.base);
+            }
+          else
+            {
+              /* Found matching region that does not allow access */
+
+              return PMP_ACCESS_DENIED;
+            }
+        }
+    }
+
+  /* Check if nothing configured at all ? */
+
+  if (size == orgsize)
+    {
+      return PMP_ACCESS_OFF;
+    }
+
+  /* If size is non-positive, the requested range is accessible */
+
+  if (size <= 0)
+    {
+      return PMP_ACCESS_FULL;
+    }
+
+  /* The requested range is either fully or partially inaccessible */
+
+  return PMP_ACCESS_DENIED;
+}
+
+/****************************************************************************
+ * Name: riscv_configured_pmp_regions
+ *
+ * Description:
+ *   Count amount of configured PMP regions, note: is not atomic
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *   Amount of configured PMP regions
+ *
+ ****************************************************************************/
+
+int riscv_configured_pmp_regions(void)
+{
+  pmp_entry_t   entry;
+  unsigned int  region;
+  int           ret = 0;
+
+  for (region = 0; region < 16; region++)
+    {
+      pmp_read(region, &entry);
+
+      if (entry.mode != PMPCFG_A_OFF)
+        {
+          ret++;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: riscv_next_free_pmp_region
+ *
+ * Description:
+ *   Returns next free PMP region, note: is not atomic
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *   Next free PMP region, or -1 if none found
+ *
+ ****************************************************************************/
+
+int riscv_next_free_pmp_region(void)
+{
+  pmp_entry_t   entry;
+  unsigned int  region;
+
+  for (region = 0; region < 16; region++)
+    {
+      pmp_read(region, &entry);
+
+      if (entry.mode == PMPCFG_A_OFF)
+        {
+          return region;
+        }
+    }
+
+  return -1;
 }
diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig
index 8074909..3c03635 100755
--- a/arch/risc-v/src/mpfs/Kconfig
+++ b/arch/risc-v/src/mpfs/Kconfig
@@ -312,3 +312,17 @@ config MPFS_DMA
 menu "MPFS Others"
 
 endmenu
+
+# Override the default values for MPU / PMP parameters here
+
+config ARCH_MPU_MIN_BLOCK_SIZE
+       default 4096
+
+config ARCH_MPU_HAS_TOR
+       default n
+
+config ARCH_MPU_HAS_NO4
+       default n
+
+config ARCH_MPU_HAS_NAPOT
+       default y
diff --git a/arch/risc-v/src/mpfs/mpfs_userspace.c 
b/arch/risc-v/src/mpfs/mpfs_userspace.c
index c69cb1c..c375d59 100755
--- a/arch/risc-v/src/mpfs/mpfs_userspace.c
+++ b/arch/risc-v/src/mpfs/mpfs_userspace.c
@@ -39,11 +39,20 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define PMP_UFLASH_FLAGS    (PMPCFG_A_NAPOT | PMPCFG_X | PMPCFG_R)
+#define PMP_USRAM_FLAGS     (PMPCFG_A_NAPOT | PMPCFG_W | PMPCFG_R)
+
+#define UFLASH_START        (uintptr_t)&__uflash_start
+#define UFLASH_SIZE         (uintptr_t)&__uflash_size
+#define USRAM_START         (uintptr_t)&__usram_start
+#define USRAM_SIZE          (uintptr_t)&__usram_size
+
 /* Physical and virtual addresses to page tables (vaddr = paddr mapping) */
 
-#define PGT_BASE_PADDR      (uint64_t)&m_l1_pgtable
+#define PGT_L1_PBASE        (uint64_t)&m_l1_pgtable
 #define PGT_L2_PBASE        (uint64_t)&m_l2_pgtable
 #define PGT_L3_PBASE        (uint64_t)&m_l3_pgtable
+#define PGT_L1_VBASE        PGT_L1_PBASE
 #define PGT_L2_VBASE        PGT_L2_PBASE
 #define PGT_L3_VBASE        PGT_L3_PBASE
 
@@ -52,6 +61,11 @@
 #define MMU_UFLASH_FLAGS    (PTE_R | PTE_X | PTE_U | PTE_G)
 #define MMU_USRAM_FLAGS     (PTE_R | PTE_W | PTE_U | PTE_G)
 
+/* Kernel RAM needs to be opened (the page tables) */
+
+#define KSRAM_START         (uintptr_t)&__ksram_start
+#define KSRAM_SIZE          (uintptr_t)&__ksram_size
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -178,9 +192,8 @@ static void configure_mpu(void)
   /* Configure the PMP to permit user-space access to its ROM and RAM.
    *
    * Note: PMP by default revokes access, thus if different privilege modes
-   * are in use (mstatus.mprv is set), the the user space _must_ be granted
-   * access here, otherwise an exception will fire when the user space task
-   * is started.
+   * are in use, the user space _must_ be granted access here, otherwise
+   * an exception will fire when the user space task is started.
    *
    * Note: according to the Polarfire reference manual, address bits [1:0]
    * are not considered (due to 4 octet alignment), so strictly they don't
@@ -198,19 +211,46 @@ static void configure_mpu(void)
    *
    */
 
-  riscv_config_pmp_region(0, PMPCFG_A_NAPOT | PMPCFG_X | PMPCFG_R,
-                          (uintptr_t)&__uflash_start,
-                          (uintptr_t)&__uflash_size);
+  int ret;
+  int idx;
+
+  /* First, test access to user flash */
+
+  ret = riscv_check_pmp_access(PMP_UFLASH_FLAGS, UFLASH_START, UFLASH_SIZE);
+
+  /* No access or partial access means we must crash */
+
+  DEBUGASSERT(ret != PMP_ACCESS_DENIED);
 
-  riscv_config_pmp_region(1, PMPCFG_A_NAPOT | PMPCFG_W | PMPCFG_R,
-                          (uintptr_t)&__usram_start,
-                          (uintptr_t)&__usram_size);
+  if (ret == PMP_ACCESS_OFF)
+    {
+      idx = riscv_next_free_pmp_region();
+      DEBUGASSERT(idx >= 0);
+      riscv_config_pmp_region(idx, PMP_UFLASH_FLAGS, UFLASH_START,
+                              UFLASH_SIZE);
+    }
+
+  /* Then, test access to user RAM */
+
+  ret = riscv_check_pmp_access(PMP_USRAM_FLAGS, USRAM_START, USRAM_SIZE);
+  DEBUGASSERT(ret != PMP_ACCESS_DENIED);
+  if (ret == PMP_ACCESS_OFF)
+    {
+      idx = riscv_next_free_pmp_region();
+      DEBUGASSERT(idx >= 0);
+      riscv_config_pmp_region(idx, PMP_USRAM_FLAGS, USRAM_START, USRAM_SIZE);
+    }
 
   /* The supervisor must have access to the page tables */
 
-  riscv_config_pmp_region(2, PMPCFG_A_NAPOT | PMPCFG_W | PMPCFG_R,
-                          (uintptr_t)&__ksram_start,
-                          (uintptr_t)&__ksram_size);
+  ret = riscv_check_pmp_access(PMP_USRAM_FLAGS, KSRAM_START, KSRAM_SIZE);
+  DEBUGASSERT(ret != PMP_ACCESS_DENIED);
+  if (ret == PMP_ACCESS_OFF)
+    {
+      idx = riscv_next_free_pmp_region();
+      DEBUGASSERT(idx >= 0);
+      riscv_config_pmp_region(idx, PMP_USRAM_FLAGS, KSRAM_START, KSRAM_SIZE);
+    }
 }
 
 /****************************************************************************
@@ -228,24 +268,22 @@ static void configure_mmu(void)
 
   /* Setup the L3 references for executable memory */
 
-  mmu_ln_map_region(3, PGT_L3_VBASE, (uintptr_t)&__uflash_start,
-                    (uintptr_t)&__uflash_start, (uintptr_t)&__uflash_size,
-                    MMU_UFLASH_FLAGS);
+  mmu_ln_map_region(3, PGT_L3_VBASE, UFLASH_START, UFLASH_START,
+                    UFLASH_SIZE, MMU_UFLASH_FLAGS);
 
   /* Setup the L3 references for data memory */
 
-  mmu_ln_map_region(3, PGT_L3_VBASE, (uintptr_t)&__usram_start,
-                    (uintptr_t)&__usram_start, (uintptr_t)&__usram_size,
-                    MMU_USRAM_FLAGS);
+  mmu_ln_map_region(3, PGT_L3_VBASE, USRAM_START, USRAM_START,
+                    USRAM_SIZE, MMU_USRAM_FLAGS);
 
   /* Setup the L2 and L1 references */
 
   mmu_ln_setentry(2, PGT_L2_VBASE, PGT_L3_PBASE, PGT_L3_VBASE, PTE_G);
-  mmu_ln_setentry(1, PGT_BASE_PADDR, PGT_L2_PBASE, PGT_L2_VBASE, PTE_G);
+  mmu_ln_setentry(1, PGT_L1_VBASE, PGT_L2_PBASE, PGT_L2_VBASE, PTE_G);
 
   /* Enable MMU */
 
-  mmu_enable(PGT_BASE_PADDR, 0);
+  mmu_enable(PGT_L1_PBASE, 0);
 }
 
 #endif /* CONFIG_BUILD_PROTECTED */

Reply via email to