You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2021/09/02 12:17:30 UTC

[incubator-nuttx] branch master updated: arch:xtensa: add xtensa mpu support

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

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


The following commit(s) were added to refs/heads/master by this push:
     new fd9ce01  arch:xtensa: add xtensa mpu support
fd9ce01 is described below

commit fd9ce0137e644e10e343479ee6ccb7a51a448a2f
Author: zhuyanlin <zh...@xiaomi.com>
AuthorDate: Wed Sep 1 21:37:15 2021 +0800

    arch:xtensa: add xtensa mpu support
    
    Add support for Xtensa Memory Protect Unit.
    
    Change-Id: I27e2f05daae24429ef7513d843b4f217daeefa0d
---
 arch/xtensa/src/common/mpu.h        | 374 ++++++++++++++++++++++++++++++++++++
 arch/xtensa/src/common/xtensa_mpu.c | 138 +++++++++++++
 2 files changed, 512 insertions(+)

diff --git a/arch/xtensa/src/common/mpu.h b/arch/xtensa/src/common/mpu.h
new file mode 100644
index 0000000..75d1ae3
--- /dev/null
+++ b/arch/xtensa/src/common/mpu.h
@@ -0,0 +1,374 @@
+/****************************************************************************
+ * arch/xtensa/src/common/mpu.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_XTENSA_SRC_COMMON_XTENSA_MPU_H
+#define __ARCH_XTENSA_SRC_COMMON_XTENSA_MPU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <arch/chip/core-isa.h>
+
+#ifndef __ASSEMBLY__
+#  include <sys/types.h>
+#  include <stdint.h>
+#  include <stdbool.h>
+#  include <assert.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MPU_VADDR_MASK ~(XCHAL_MPU_ALIGN - (1))
+
+#define MPU_ENTRY_AS(vaddr, valid) \
+        (((vaddr) & MPU_VADDR_MASK) | \
+        ((valid) & (0x1)))
+
+#define MPU_ENTRY_AR(access, memtype) \
+        (((ENCODE_MEMORY_TYPE(memtype)) << (12)) | \
+        (((access) & (0xf)) << (8)))
+
+/****************************************************************************
+ *  MPU access rights constants
+ ****************************************************************************/
+
+#define MPU_AR_NONE                  (0)    /* no access */
+#define MPU_AR_R                     (4)    /* Kernel read, User no access*/
+#define MPU_AR_RX                    (5)    /* Kernel read/execute, User no access */
+#define MPU_AR_RW                    (6)    /* Kernel read/write, User no access */
+#define MPU_AR_RWX                   (7)    /* Kernel read/write/execute, User no access */
+#define MPU_AR_Ww                    (8)    /* Kernel write, User write */
+#define MPU_AR_RWrwx                 (9)    /* Kernel read/write , User read/write/execute */
+#define MPU_AR_RWr                   (10)   /* Kernel read/write, User read */
+#define MPU_AR_RWXrx                 (11)   /* Kernel read/write/execute, User read/execute */
+#define MPU_AR_Rr                    (12)   /* Kernel read, User read */
+#define MPU_AR_RXrx                  (13)   /* Kernel read/execute, User read/execute */
+#define MPU_AR_RWrw                  (14)   /* Kernel read/write, User read/write */
+#define MPU_AR_RWXrwx                (15)   /* Kernel read/write/execute, User read/write/execute */
+#define MPU_AR_WIDTH                 4      /* Bits used to encode access rights */
+
+/****************************************************************************
+ * MPU access memtype constants
+ ****************************************************************************/
+
+#define MPU_MEM_DEVICE               (0x00008000)
+#define MPU_MEM_NON_CACHEABLE        (0x00090000)
+#define MPU_MEM_WRITETHRU_NOALLOC    (0x00080000)
+#define MPU_MEM_WRITETHRU            (0x00040000)
+#define MPU_MEM_WRITETHRU_WRITEALLOC (0x00060000)
+#define MPU_MEM_WRITEBACK_NOALLOC    (0x00050000)
+#define MPU_MEM_WRITEBACK            (0x00070000)
+#define MPU_MEM_INTERRUPTIBLE        (0x08000000)
+#define MPU_MEM_BUFFERABLE           (0x01000000)
+#define MPU_MEM_NON_SHAREABLE        (0x00000000)
+#define MPU_MEM_INNER_SHAREABLE      (0x02000000)
+#define MPU_MEM_OUTER_SHAREABLE      (0x04000000)
+#define MPU_MEM_SYSTEM_SHAREABLE     (0x06000000)
+
+/****************************************************************************
+ * Layout of the MPU memory type specifier for: ENCODE_MEMORY_TYPE()
+ *
+ * Bits 0-3  - reserved for pass through of accessRights
+ * Bits 4-12 - reserved for pass through of memoryType bits
+ * Bit  13   - indicates to use existing access rights of region
+ * Bit  14   - indicates to use existing memory type of region
+ * Bit  15   - indicates device
+ * Bit  16-19- system cache properties
+ * Bit  20-23- local cache properties
+ * Bit  24   - indicates bufferable
+ * Bit  25-26- encodes shareability (1=inner, 2=outer, 3=system)
+ * Bit  27   - indicates interruptible
+ * Bits 28-31- reserved for future use
+ ****************************************************************************/
+
+#define SYSTEM_CACHE_BITS            (0x000f0000)
+#define LOCAL_CACHE_BITS             (0x00f00000)
+#define SYSTEM_RWC_MASK              (0x00070000)
+#define LOCAL_RWC_MASK               (0x00700000)
+#define SHIFT_RWC                    16
+
+#define MEM_ANY_SHAREABLE(x) (((x & MPU_MEM_SYSTEM_SHAREABLE) \
+        != (0)) ? (1) : (0))
+
+#define MEM_INNER_SHAREABLE(x) (((x & MPU_MEM_SYSTEM_SHAREABLE) \
+        == MPU_MEM_INNER_SHAREABLE) ? (1) : (0))
+
+#define MEM_IS_BUFFERABLE(x) (((x & MPU_MEM_BUFFERABLE) != (0)) ? \
+        (1) : (0))
+
+#define MEM_IS_DEVICE(x) (((x & MPU_MEM_DEVICE) != (0)) ? (1) : (0))
+
+#define NON_CACHEABLE_DOMAIN(x) \
+        ((MEM_IS_DEVICE(x) != (0)) || \
+        (MEM_ANY_SHAREABLE(x) != (0)) ? (0x3) : (0))
+
+#define CACHEABLE_DOMAIN(x)  ((MEM_ANY_SHAREABLE(x) != (0)) ? \
+        (0x3) : (0x1))
+
+#define MEM_CACHE_MASK(x) (x & SYSTEM_CACHE_BITS)
+
+#define IS_SYSTEM_NONCACHEABLE(x) \
+        (((MEM_CACHE_MASK(x) & MPU_MEM_NON_CACHEABLE) == \
+                MPU_MEM_NON_CACHEABLE) ? (1) : (0))
+
+#define ENCODE_DEVICE(x) \
+        (((((x & MPU_MEM_INTERRUPTIBLE) != (0)) \
+        ? (1) : (0)) << 3) | \
+        ((NON_CACHEABLE_DOMAIN(x) << 1) | MEM_IS_BUFFERABLE(x)))
+
+#define ENCODE_SYSTEM_NONCACHEABLE(x) \
+        (((x & LOCAL_CACHE_BITS) != (0)) && \
+        (((x & LOCAL_CACHE_BITS) >> 4) != MPU_MEM_NON_CACHEABLE)) ? \
+        ((0x89) | (((x) & LOCAL_CACHE_BITS) >> SHIFT_RWC)) :\
+        ((((0x18) | (NON_CACHEABLE_DOMAIN(x) << 1)) \
+                | MEM_IS_BUFFERABLE(x)))
+
+#define ENCODE_SYSTEM_CACHEABLE(x) \
+        (((((x & LOCAL_CACHE_BITS) >> 4) & MPU_MEM_NON_CACHEABLE) == \
+               MPU_MEM_NON_CACHEABLE) ? \
+        (CACHEABLE_DOMAIN(x) << 4) : \
+        ENCODE_SYSTEM_CACHEABLE_LOCAL_CACHEABLE(x)) | \
+        ((MEM_INNER_SHAREABLE(x) << 3) | \
+                 ((MEM_CACHE_MASK(x) & SYSTEM_RWC_MASK) \
+                 >> SHIFT_RWC))
+
+#define ENCODE_SYSTEM_CACHEABLE_LOCAL_CACHEABLE(x) \
+        ((CACHEABLE_DOMAIN(x) << 7) | (((((x & LOCAL_CACHE_BITS) != (0)) ? \
+                (x & LOCAL_CACHE_BITS) : \
+                ((MEM_CACHE_MASK(x) << 4)) \
+        & (LOCAL_RWC_MASK)) >> SHIFT_RWC)))
+
+#define ENCODE_MEMORY_TYPE(x) \
+        (((x & (0xffffe000)) != (0)) ? \
+        ((MEM_IS_DEVICE((x)) != (0)) ? ENCODE_DEVICE((x)) : \
+        ((IS_SYSTEM_NONCACHEABLE((x)) != (0)) ? \
+        ENCODE_SYSTEM_NONCACHEABLE((x)) : \
+        ENCODE_SYSTEM_CACHEABLE((x)))) : x)
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: mpu_allocregion
+ *
+ * Description:
+ *  Allocate the next region
+ *
+ ****************************************************************************/
+
+unsigned int mpu_allocregion(void);
+
+/****************************************************************************
+ * Name: mpu_control
+ *
+ * Description:
+ *   Configure and enable (or disable) the MPU
+ *
+ ****************************************************************************/
+
+void mpu_control(bool enable);
+
+/****************************************************************************
+ * Name: mpu_configure_region
+ *
+ * Description:
+ *   Configure a region for privileged, strongly ordered memory
+ *
+ ****************************************************************************/
+
+void mpu_configure_region(uintptr_t base, size_t size,
+            uint8_t acc, uint16_t memtype);
+
+/****************************************************************************
+ * Name: mpu_priv_stronglyordered
+ *
+ * Description:
+ *   Configure a region for privileged, strongly ordered memory
+ *
+ ****************************************************************************/
+
+#define mpu_priv_stronglyordered(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RWX, \
+                          MPU_MEM_DEVICE); \
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_user_flash
+ *
+ * Description:
+ *   Configure a region for user program flash
+ *
+ ****************************************************************************/
+
+#define mpu_user_flash(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RXrx, \
+                          MPU_MEM_WRITEBACK);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_priv_flash
+ *
+ * Description:
+ *   Configure a region for privileged program flash
+ *
+ ****************************************************************************/
+
+#define mpu_priv_flash(base, size) \
+  do \
+    { \
+      /* The configure the region */   \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RX, \
+                          MPU_MEM_WRITEBACK);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_user_intsram
+ *
+ * Description:
+ *   Configure a region as user internal SRAM
+ *
+ ****************************************************************************/
+
+#define mpu_user_intsram(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RWXrwx, \
+                          MPU_MEM_WRITEBACK);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_priv_intsram
+ *
+ * Description:
+ *   Configure a region as privileged internal SRAM
+ *
+ ****************************************************************************/
+
+#define mpu_priv_intsram(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size,\
+                          MPU_AR_RWX, \
+                          MPU_MEM_WRITETHRU);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_user_extsram
+ *
+ * Description:
+ *   Configure a region as user external SRAM
+ *
+ ****************************************************************************/
+
+#define mpu_user_extsram(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RWXrwx, \
+                          MPU_MEM_WRITETHRU);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_priv_extsram
+ *
+ * Description:
+ *   Configure a region as privileged external SRAM
+ *
+ ****************************************************************************/
+
+#define mpu_priv_extsram(base, size) \
+  do \
+    { \
+      /* The configure the region */ \
+      mpu_configure_region(base, size,  \
+                          MPU_AR_RWX, \
+                          MPU_MEM_WRITETHRU);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_peripheral
+ *
+ * Description:
+ *   Configure a region as privileged peripheral address space
+ *
+ ****************************************************************************/
+
+#define mpu_peripheral(base, size) \
+  do \
+    { \
+      /* Then configure the region */  \
+      mpu_configure_region(base, size, \
+                          MPU_AR_RW, \
+                          MPU_MEM_DEVICE);\
+    } while (0)
+
+/****************************************************************************
+ * Name: mpu_user_peripheral
+ *
+ * Description:
+ *   Configure a region as user peripheral address space
+ *
+ ****************************************************************************/
+
+#define mpu_user_peripheral(base, size) \
+  do \
+    { \
+      /* Then configure the region */     \
+      mpu_configure_region(base, size,    \
+                          MPU_AR_RWrw,  \
+                          MPU_MEM_DEVICE);\
+    } while (0)
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_XTENSA_SRC_COMMON_XTENSA_MPU_H */
diff --git a/arch/xtensa/src/common/xtensa_mpu.c b/arch/xtensa/src/common/xtensa_mpu.c
new file mode 100644
index 0000000..39f2c85
--- /dev/null
+++ b/arch/xtensa/src/common/xtensa_mpu.c
@@ -0,0 +1,138 @@
+/****************************************************************************
+ * arch/xtensa/src/common/xtensa_mpu.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 <nuttx/config.h>
+
+#include "mpu.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Cache for mpu base address in entry */
+
+static uint32_t xtensa_mpu_base[XCHAL_MPU_ENTRIES];
+
+/* The next available region number in decreasing way */
+
+static uint8_t g_region = XCHAL_MPU_ENTRIES;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mpu_allocregion
+ *
+ * Description:
+ *   Allocate the next region
+ *
+ * Assumptions:
+ *   - Regions are never deallocated
+ *   - Regions are only allocated early in initialization, so no special
+ *     protection against re-entrancy is required;
+ *
+ ****************************************************************************/
+
+unsigned int mpu_allocregion(void)
+{
+  DEBUGASSERT((unsigned int)g_region >= 0);
+  return (unsigned int)--g_region;
+}
+
+/****************************************************************************
+ * Name: mpu_control
+ *
+ * Description:
+ *   Configure and enable (or disable) the MPU
+ *
+ ****************************************************************************/
+
+void mpu_control(bool enable)
+{
+  uint32_t regval = 0;
+
+  if (enable)
+    {
+      uint32_t i;
+      for (i = XCHAL_MPU_ENTRIES - 1; i >= g_region; i--)
+        {
+          regval |= (1 << i);
+        }
+    }
+
+  __asm__ __volatile__ ("wsr %0, mpuenb\n" : : "r"(regval));
+}
+
+/****************************************************************************
+ * Name: mpu_configure_region
+ *
+ * Description:
+ *   Configure a region
+ *
+ ****************************************************************************/
+
+void mpu_configure_region(uintptr_t base, size_t size,
+            uint8_t acc, uint16_t memtype)
+{
+  unsigned int region = mpu_allocregion();
+  uint32_t at;
+  uint32_t as;
+
+  /* Ensure address not overlay
+   *
+   * Xtensa ISA Reference Manual B4.6.5.3:
+   * The lowest address of each foregound segment
+   * must be no smaller than the lowest address of the
+   * preceding foregroud segment in numerical order.
+   */
+
+  if (region < (XCHAL_MPU_ENTRIES - 1))
+    {
+      DEBUGASSERT(base < xtensa_mpu_base[region + 1]);
+    }
+
+  /* Now only setup MPU entry, enable mpu in mpu_control */
+
+  as = MPU_ENTRY_AS(base, 0);
+  at = MPU_ENTRY_AR(acc, memtype);
+
+  /* Set segment bits */
+
+  at |= region;
+
+  /* update mpu entry .. requires an memw on same cache line */
+
+  __asm__ __volatile__
+    (
+      "\tj 1f\n"
+      "\t.align 16\n"
+      "\t1: memw\n"
+      "\twptlb %0, %1\n"
+      :
+      : "a" (at), "a"(as)
+    );
+
+  xtensa_mpu_base[region] = base;
+}