arch: arc: add support of mpu v6
Add support of ARC mpu v6
* minimal region size down to 32 bytes
* maximal region number up to 32
* not support uncacheable region and volatile uncached region
* clean up mpu code for better readablity
Signed-off-by: Yuguo Zou <yuguo.zou@synopsys.com>
diff --git a/arch/arc/core/mpu/Kconfig b/arch/arc/core/mpu/Kconfig
index 70a9850..38b9c58 100644
--- a/arch/arc/core/mpu/Kconfig
+++ b/arch/arc/core/mpu/Kconfig
@@ -5,11 +5,12 @@
config ARC_MPU_VER
int "ARC MPU version"
- range 2 4
+ range 2 6
default 2
help
ARC MPU has several versions. For MPU v2, the minimum region is 2048 bytes;
- For MPU v3 and v4, the minimum region is 32 bytes
+ For other versions, the minimum region is 32 bytes; v4 has secure features,
+ v6 supports up to 32 regions.
config ARC_CORE_MPU
bool "ARC Core MPU functionalities"
@@ -31,8 +32,8 @@
select SRAM_REGION_PERMISSIONS
select ARC_CORE_MPU
select THREAD_STACK_INFO
- select GEN_PRIV_STACKS if ARC_MPU_VER = 2
- select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if ARC_MPU_VER = 2
+ select GEN_PRIV_STACKS if ARC_MPU_VER != 4
+ select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if ARC_MPU_VER !=4
select MPU_REQUIRES_NON_OVERLAPPING_REGIONS if ARC_MPU_VER = 4
help
Target has ARC MPU (currently only works for EMSK 2.2/2.3 ARCEM7D)
diff --git a/arch/arc/core/mpu/arc_mpu.c b/arch/arc/core/mpu/arc_mpu.c
index 9fbe49d..111bc0f 100644
--- a/arch/arc/core/mpu/arc_mpu.c
+++ b/arch/arc/core/mpu/arc_mpu.c
@@ -52,8 +52,8 @@
}
}
-#if CONFIG_ARC_MPU_VER == 2
-#include "arc_mpu_v2_internal.h"
-#elif CONFIG_ARC_MPU_VER == 4
+#if CONFIG_ARC_MPU_VER == 4
#include "arc_mpu_v4_internal.h"
+#else
+#include "arc_mpu_common_internal.h"
#endif
diff --git a/arch/arc/core/mpu/arc_mpu_common_internal.h b/arch/arc/core/mpu/arc_mpu_common_internal.h
new file mode 100644
index 0000000..e6e2174
--- /dev/null
+++ b/arch/arc/core/mpu/arc_mpu_common_internal.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2021 Synopsys.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_
+#define ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_
+
+#if CONFIG_ARC_MPU_VER == 2 || CONFIG_ARC_MPU_VER == 3
+#include "arc_mpu_v2_internal.h"
+#elif CONFIG_ARC_MPU_VER == 6
+#include "arc_mpu_v6_internal.h"
+#else
+#error "Unsupported MPU version"
+#endif
+
+/**
+ * @brief configure the base address and size for an MPU region
+ *
+ * @param type MPU region type
+ * @param base base address in RAM
+ * @param size size of the region
+ */
+static inline int _mpu_configure(uint8_t type, uint32_t base, uint32_t size)
+{
+ int32_t region_index = get_region_index_by_type(type);
+ uint32_t region_attr = get_region_attr_by_type(type);
+
+ LOG_DBG("Region info: 0x%x 0x%x", base, size);
+
+ if (region_attr == 0U || region_index < 0) {
+ return -EINVAL;
+ }
+
+ /*
+ * For ARC MPU, MPU regions can be overlapped, smaller
+ * region index has higher priority.
+ */
+ _region_init(region_index, base, size, region_attr);
+
+ return 0;
+}
+
+/* ARC Core MPU Driver API Implementation for ARC MP */
+
+/**
+ * @brief enable the MPU
+ */
+void arc_core_mpu_enable(void)
+{
+ /* Enable MPU */
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
+ z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) | AUX_MPU_EN_ENABLE);
+}
+
+/**
+ * @brief disable the MPU
+ */
+void arc_core_mpu_disable(void)
+{
+ /* Disable MPU */
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
+ z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & AUX_MPU_EN_DISABLE);
+}
+
+/**
+ * @brief configure the thread's MPU regions
+ *
+ * @param thread the target thread
+ */
+void arc_core_mpu_configure_thread(struct k_thread *thread)
+{
+#if defined(CONFIG_USERSPACE)
+ /* configure stack region of user thread */
+ if (thread->base.user_options & K_USER) {
+ LOG_DBG("configure user thread %p's stack", thread);
+ if (_mpu_configure(THREAD_STACK_USER_REGION,
+ (uint32_t)thread->stack_info.start,
+ thread->stack_info.size) < 0) {
+ LOG_ERR("user thread %p's stack failed", thread);
+ return;
+ }
+ }
+
+ LOG_DBG("configure thread %p's domain", thread);
+ arc_core_mpu_configure_mem_domain(thread);
+#endif
+}
+
+
+/**
+ * @brief configure the default region
+ *
+ * @param region_attr region attribute of default region
+ */
+void arc_core_mpu_default(uint32_t region_attr)
+{
+ uint32_t val = z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & (~AUX_MPU_RDP_ATTR_MASK);
+
+ region_attr &= AUX_MPU_RDP_ATTR_MASK;
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN, region_attr | val);
+}
+
+/**
+ * @brief configure the MPU region
+ *
+ * @param index MPU region index
+ * @param base base address
+ * @param region_attr region attribute
+ */
+int arc_core_mpu_region(uint32_t index, uint32_t base, uint32_t size, uint32_t region_attr)
+{
+ if (index >= get_num_regions()) {
+ return -EINVAL;
+ }
+
+ region_attr &= AUX_MPU_RDP_ATTR_MASK;
+
+ _region_init(index, base, size, region_attr);
+
+ return 0;
+}
+
+#if defined(CONFIG_USERSPACE)
+
+/**
+ * @brief configure MPU regions for the memory partitions of the memory domain
+ *
+ * @param thread the thread which has memory domain
+ */
+void arc_core_mpu_configure_mem_domain(struct k_thread *thread)
+{
+ int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
+ uint32_t num_partitions;
+ struct k_mem_partition *pparts;
+ struct k_mem_domain *mem_domain = NULL;
+
+ if (thread) {
+ mem_domain = thread->mem_domain_info.mem_domain;
+ }
+
+ if (mem_domain) {
+ LOG_DBG("configure domain: %p", mem_domain);
+ num_partitions = mem_domain->num_partitions;
+ pparts = mem_domain->partitions;
+ } else {
+ LOG_DBG("disable domain partition regions");
+ num_partitions = 0U;
+ pparts = NULL;
+ }
+
+ for (; region_index >= 0; region_index--) {
+ if (num_partitions) {
+ LOG_DBG("set region 0x%x 0x%lx 0x%x",
+ region_index, pparts->start, pparts->size);
+ _region_init(region_index, pparts->start, pparts->size, pparts->attr);
+ num_partitions--;
+ } else {
+ /* clear the left mpu entries */
+ _region_init(region_index, 0, 0, 0);
+ }
+ pparts++;
+ }
+}
+
+/**
+ * @brief remove MPU regions for the memory partitions of the memory domain
+ *
+ * @param mem_domain the target memory domain
+ */
+void arc_core_mpu_remove_mem_domain(struct k_mem_domain *mem_domain)
+{
+ ARG_UNUSED(mem_domain);
+
+ int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
+
+ for (; region_index >= 0; region_index--) {
+ _region_init(region_index, 0, 0, 0);
+ }
+}
+
+/**
+ * @brief reset MPU region for a single memory partition
+ *
+ * @param domain the target memory domain
+ * @param partition_id memory partition id
+ */
+void arc_core_mpu_remove_mem_partition(struct k_mem_domain *domain, uint32_t part_id)
+{
+ ARG_UNUSED(domain);
+
+ int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
+
+ LOG_DBG("disable region 0x%x", region_index + part_id);
+ /* Disable region */
+ _region_init(region_index + part_id, 0, 0, 0);
+}
+
+/**
+ * @brief get the maximum number of free regions for memory domain partitions
+ */
+int arc_core_mpu_get_max_domain_partition_regions(void)
+{
+ return get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION) + 1;
+}
+
+/**
+ * @brief validate the given buffer is user accessible or not
+ */
+int arc_core_mpu_buffer_validate(void *addr, size_t size, int write)
+{
+ /*
+ * For ARC MPU, smaller region number takes priority.
+ * we can stop the iteration immediately once we find the
+ * matched region that grants permission or denies access.
+ *
+ */
+ for (int r_index = 0; r_index < get_num_regions(); r_index++) {
+ if (!_is_enabled_region(r_index) || !_is_in_region(r_index, (uint32_t)addr, size)) {
+ continue;
+ }
+
+ if (_is_user_accessible_region(r_index, write)) {
+ return 0;
+ } else {
+ return -EPERM;
+ }
+ }
+
+ return -EPERM;
+}
+#endif /* CONFIG_USERSPACE */
+
+/* ARC MPU Driver Initial Setup */
+/*
+ * @brief MPU default initialization and configuration
+ *
+ * This function provides the default configuration mechanism for the Memory
+ * Protection Unit (MPU).
+ */
+static int arc_mpu_init(const struct device *arg)
+{
+ ARG_UNUSED(arg);
+
+ uint32_t num_regions = get_num_regions();
+
+ if (mpu_config.num_regions > num_regions) {
+ __ASSERT(0, "Request to configure: %u regions (supported: %u)\n",
+ mpu_config.num_regions, num_regions);
+ return -EINVAL;
+ }
+
+ /* Disable MPU */
+ arc_core_mpu_disable();
+
+ /*
+ * the MPU regions are filled in the reverse order.
+ * According to ARCv2 ISA, the MPU region with smaller
+ * index has higher priority. The static background MPU
+ * regions in mpu_config will be in the bottom. Then
+ * the special type regions will be above.
+ */
+ int r_index = num_regions - mpu_config.num_regions;
+
+ /* clear all the regions first */
+ for (uint32_t i = 0U; i < r_index; i++) {
+ _region_init(i, 0, 0, 0);
+ }
+
+ /* configure the static regions */
+ for (uint32_t i = 0U; i < mpu_config.num_regions; i++) {
+ _region_init(r_index, mpu_config.mpu_regions[i].base,
+ mpu_config.mpu_regions[i].size, mpu_config.mpu_regions[i].attr);
+ r_index++;
+ }
+
+ /* default region: no read, write and execute */
+ arc_core_mpu_default(0);
+
+ /* Enable MPU */
+ arc_core_mpu_enable();
+
+ return 0;
+}
+
+SYS_INIT(arc_mpu_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
+
+#endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_ */
diff --git a/arch/arc/core/mpu/arc_mpu_v2_internal.h b/arch/arc/core/mpu/arc_mpu_v2_internal.h
index 12b2c64..f59b1e9 100644
--- a/arch/arc/core/mpu/arc_mpu_v2_internal.h
+++ b/arch/arc/core/mpu/arc_mpu_v2_internal.h
@@ -6,15 +6,36 @@
#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
#define ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
-#define AUX_MPU_RDB_VALID_MASK (0x1)
-#define AUX_MPU_EN_ENABLE (0x40000000)
-#define AUX_MPU_EN_DISABLE (0xBFFFFFFF)
+#define AUX_MPU_EN_ENABLE BIT(30)
+#define AUX_MPU_EN_DISABLE ~BIT(30)
-#define AUX_MPU_RDP_REGION_SIZE(bits) \
- (((bits - 1) & 0x3) | (((bits - 1) & 0x1C) << 7))
+/*
+ * The size of the region is a 5-bit field, the three MSB bits are
+ * represented in [11:9] and the two LSB bits are represented in [1:0].
+ * Together these fields specify the size of the region in bytes:
+ * 00000-00011 Reserved
+ * 0x4 32 0x5 64 0x6 128 0x7 256
+ * 0x8 512 0x9 1k 0xA 2K 0xB 4K
+ * 0xC 8K 0xD 16K 0xE 32K 0xF 64K
+ * 0x10 128K 0x11 256K 0x12 512K 0x13 1M
+ * 0x14 2M 0x15 4M 0x16 8M 0x17 16M
+ * 0x18 32M 0x19 64M 0x1A 128M 0x1B 256M
+ * 0x1C 512M 0x1D 1G 0x1E 2G 0x1F 4G
+ *
+ * Bit ... 12 11 10 9 8 3 2 1 0
+ * ------+------------+------+---+-----------+
+ * ... | SIZE[11:9] | ATTR | R | SIZE[1:0] |
+ * ------+------------+------+---+-----------+
+ */
+/* arrange size into proper bit field in RDP aux reg*/
+#define AUX_MPU_RDP_REGION_SIZE(size) (((size - 1) & BIT_MASK(2)) | \
+ (((size - 1) & (BIT_MASK(3) << 2)) << 7))
+/* recover size from bit fields in RDP aux reg*/
+#define AUX_MPU_RDP_SIZE_SHIFT(rdp) ((rdp & BIT_MASK(2)) | (((rdp >> 9) & BIT_MASK(3)) << 2))
-#define AUX_MPU_RDP_ATTR_MASK (0x1FC)
-#define AUX_MPU_RDP_SIZE_MASK (0xE03)
+#define AUX_MPU_RDB_VALID_MASK BIT(0)
+#define AUX_MPU_RDP_ATTR_MASK (BIT_MASK(6) << 3)
+#define AUX_MPU_RDP_SIZE_MASK ((BIT_MASK(3) << 9) | BIT_MASK(2))
/* For MPU version 2, the minimum protection region size is 2048 bytes */
#if CONFIG_ARC_MPU_VER == 2
@@ -39,7 +60,7 @@
bits = ARC_FEATURE_MPU_ALIGNMENT_BITS;
}
- if ((1 << bits) < size) {
+ if (BIT(bits) < size) {
bits++;
}
@@ -72,8 +93,7 @@
*/
switch (type) {
case THREAD_STACK_USER_REGION:
- return get_num_regions() - mpu_config.num_regions
- - THREAD_STACK_REGION;
+ return get_num_regions() - mpu_config.num_regions - THREAD_STACK_REGION;
case THREAD_STACK_REGION:
case THREAD_APP_DATA_REGION:
case THREAD_DOMAIN_PARTITION_REGION:
@@ -110,14 +130,14 @@
& (~AUX_MPU_RDB_VALID_MASK);
r_size_lshift = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + r_index * 2U)
& AUX_MPU_RDP_SIZE_MASK;
- r_size_lshift = (r_size_lshift & 0x3) | ((r_size_lshift >> 7) & 0x1C);
+ r_size_lshift = AUX_MPU_RDP_SIZE_SHIFT(r_size_lshift);
r_addr_end = r_addr_start + (1 << (r_size_lshift + 1));
if (start >= r_addr_start && (start + size) <= r_addr_end) {
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/**
@@ -140,296 +160,4 @@
(AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR));
}
-/**
- * @brief configure the base address and size for an MPU region
- *
- * @param type MPU region type
- * @param base base address in RAM
- * @param size size of the region
- */
-static inline int _mpu_configure(uint8_t type, uint32_t base, uint32_t size)
-{
- int32_t region_index = get_region_index_by_type(type);
- uint32_t region_attr = get_region_attr_by_type(type);
-
- LOG_DBG("Region info: 0x%x 0x%x", base, size);
-
- if (region_attr == 0U || region_index < 0) {
- return -EINVAL;
- }
-
- /*
- * For ARC MPU v2, MPU regions can be overlapped, smaller
- * region index has higher priority.
- */
- _region_init(region_index, base, size, region_attr);
-
- return 0;
-}
-
-/* ARC Core MPU Driver API Implementation for ARC MPUv2 */
-
-/**
- * @brief enable the MPU
- */
-void arc_core_mpu_enable(void)
-{
- /* Enable MPU */
- z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
- z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) | AUX_MPU_EN_ENABLE);
-}
-
-/**
- * @brief disable the MPU
- */
-void arc_core_mpu_disable(void)
-{
- /* Disable MPU */
- z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
- z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & AUX_MPU_EN_DISABLE);
-}
-
-/**
- * @brief configure the thread's MPU regions
- *
- * @param thread the target thread
- */
-void arc_core_mpu_configure_thread(struct k_thread *thread)
-{
-#if defined(CONFIG_USERSPACE)
- /* configure stack region of user thread */
- if (thread->base.user_options & K_USER) {
- LOG_DBG("configure user thread %p's stack", thread);
- if (_mpu_configure(THREAD_STACK_USER_REGION,
- (uint32_t)thread->stack_info.start,
- thread->stack_info.size) < 0) {
- LOG_ERR("user thread %p's stack failed", thread);
- return;
- }
- }
-
- LOG_DBG("configure thread %p's domain", thread);
- arc_core_mpu_configure_mem_domain(thread);
-#endif
-}
-
-
-/**
- * @brief configure the default region
- *
- * @param region_attr region attribute of default region
- */
-void arc_core_mpu_default(uint32_t region_attr)
-{
- uint32_t val = z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) &
- (~AUX_MPU_RDP_ATTR_MASK);
-
- region_attr &= AUX_MPU_RDP_ATTR_MASK;
-
- z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN, region_attr | val);
-}
-
-/**
- * @brief configure the MPU region
- *
- * @param index MPU region index
- * @param base base address
- * @param region_attr region attribute
- */
-int arc_core_mpu_region(uint32_t index, uint32_t base, uint32_t size,
- uint32_t region_attr)
-{
- if (index >= get_num_regions()) {
- return -EINVAL;
- }
-
- region_attr &= AUX_MPU_RDP_ATTR_MASK;
-
- _region_init(index, base, size, region_attr);
-
- return 0;
-}
-
-#if defined(CONFIG_USERSPACE)
-
-/**
- * @brief configure MPU regions for the memory partitions of the memory domain
- *
- * @param thread the thread which has memory domain
- */
-void arc_core_mpu_configure_mem_domain(struct k_thread *thread)
-{
- int region_index =
- get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
- uint32_t num_partitions;
- struct k_mem_partition *pparts;
- struct k_mem_domain *mem_domain = NULL;
-
- if (thread) {
- mem_domain = thread->mem_domain_info.mem_domain;
- }
-
- if (mem_domain) {
- LOG_DBG("configure domain: %p", mem_domain);
- num_partitions = mem_domain->num_partitions;
- pparts = mem_domain->partitions;
- } else {
- LOG_DBG("disable domain partition regions");
- num_partitions = 0U;
- pparts = NULL;
- }
-
- for (; region_index >= 0; region_index--) {
- if (num_partitions) {
- LOG_DBG("set region 0x%x 0x%lx 0x%x",
- region_index, pparts->start, pparts->size);
- _region_init(region_index, pparts->start,
- pparts->size, pparts->attr);
- num_partitions--;
- } else {
- /* clear the left mpu entries */
- _region_init(region_index, 0, 0, 0);
- }
- pparts++;
- }
-}
-
-/**
- * @brief remove MPU regions for the memory partitions of the memory domain
- *
- * @param mem_domain the target memory domain
- */
-void arc_core_mpu_remove_mem_domain(struct k_mem_domain *mem_domain)
-{
- ARG_UNUSED(mem_domain);
-
- int region_index =
- get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
-
- for (; region_index >= 0; region_index--) {
- _region_init(region_index, 0, 0, 0);
- }
-}
-
-/**
- * @brief reset MPU region for a single memory partition
- *
- * @param domain the target memory domain
- * @param partition_id memory partition id
- */
-void arc_core_mpu_remove_mem_partition(struct k_mem_domain *domain,
- uint32_t part_id)
-{
- ARG_UNUSED(domain);
-
- int region_index =
- get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
-
- LOG_DBG("disable region 0x%x", region_index + part_id);
- /* Disable region */
- _region_init(region_index + part_id, 0, 0, 0);
-}
-
-/**
- * @brief get the maximum number of free regions for memory domain partitions
- */
-int arc_core_mpu_get_max_domain_partition_regions(void)
-{
- return get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION) + 1;
-}
-
-/**
- * @brief validate the given buffer is user accessible or not
- */
-int arc_core_mpu_buffer_validate(void *addr, size_t size, int write)
-{
- int r_index;
-
- /*
- * For ARC MPU v2, smaller region number takes priority.
- * we can stop the iteration immediately once we find the
- * matched region that grants permission or denies access.
- *
- */
- for (r_index = 0; r_index < get_num_regions(); r_index++) {
- if (!_is_enabled_region(r_index) ||
- !_is_in_region(r_index, (uint32_t)addr, size)) {
- continue;
- }
-
- if (_is_user_accessible_region(r_index, write)) {
- return 0;
- } else {
- return -EPERM;
- }
- }
-
- return -EPERM;
-}
-#endif /* CONFIG_USERSPACE */
-
-/* ARC MPU Driver Initial Setup */
-/*
- * @brief MPU default initialization and configuration
- *
- * This function provides the default configuration mechanism for the Memory
- * Protection Unit (MPU).
- */
-static int arc_mpu_init(const struct device *arg)
-{
- ARG_UNUSED(arg);
-
- uint32_t num_regions;
- uint32_t i;
-
- num_regions = get_num_regions();
-
- /* ARC MPU supports up to 16 Regions */
- if (mpu_config.num_regions > num_regions) {
- __ASSERT(0,
- "Request to configure: %u regions (supported: %u)\n",
- mpu_config.num_regions, num_regions);
- return -EINVAL;
- }
-
- /* Disable MPU */
- arc_core_mpu_disable();
-
- int r_index;
- /*
- * the MPU regions are filled in the reverse order.
- * According to ARCv2 ISA, the MPU region with smaller
- * index has higher priority. The static background MPU
- * regions in mpu_config will be in the bottom. Then
- * the special type regions will be above.
- *
- */
- r_index = num_regions - mpu_config.num_regions;
-
- /* clear all the regions first */
- for (i = 0U; i < r_index; i++) {
- _region_init(i, 0, 0, 0);
- }
-
- /* configure the static regions */
- for (i = 0U; i < mpu_config.num_regions; i++) {
- _region_init(r_index,
- mpu_config.mpu_regions[i].base,
- mpu_config.mpu_regions[i].size,
- mpu_config.mpu_regions[i].attr);
- r_index++;
- }
-
- /* default region: no read, write and execute */
- arc_core_mpu_default(0);
-
- /* Enable MPU */
- arc_core_mpu_enable();
-
- return 0;
-}
-
-SYS_INIT(arc_mpu_init, PRE_KERNEL_1,
- CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
-
#endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_ */
diff --git a/arch/arc/core/mpu/arc_mpu_v6_internal.h b/arch/arc/core/mpu/arc_mpu_v6_internal.h
new file mode 100644
index 0000000..1dbd50b
--- /dev/null
+++ b/arch/arc/core/mpu/arc_mpu_v6_internal.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2021 Synopsys.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V6_INTERNAL_H_
+#define ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V6_INTERNAL_H_
+
+#define AUX_MPU_EN_BANK_MASK BIT(0)
+#define AUX_MPU_EN_IC BIT(12)
+#define AUX_MPU_EN_DC BIT(13)
+#define AUX_MPU_EN_ENABLE BIT(30)
+#define AUX_MPU_EN_DISABLE ~BIT(30)
+
+/*
+ * The size of the region is a 5-bit field, the three MSB bits are
+ * represented in [11:9] and the two LSB bits are represented in [1:0].
+ * Together these fields specify the size of the region in bytes:
+ * 00000-00011 Reserved
+ * 0x4 32 0x5 64 0x6 128 0x7 256
+ * 0x8 512 0x9 1k 0xA 2K 0xB 4K
+ * 0xC 8K 0xD 16K 0xE 32K 0xF 64K
+ * 0x10 128K 0x11 256K 0x12 512K 0x13 1M
+ * 0x14 2M 0x15 4M 0x16 8M 0x17 16M
+ * 0x18 32M 0x19 64M 0x1A 128M 0x1B 256M
+ * 0x1C 512M 0x1D 1G 0x1E 2G 0x1F 4G
+ *
+ * Bit ... 12 11 10 9 8 3 2 1 0
+ * ------+------------+------+---+-----------+
+ * ... | SIZE[11:9] | ATTR | R | SIZE[1:0] |
+ * ------+------------+------+---+-----------+
+ */
+/* arrange size into proper bit field in RDP aux reg*/
+#define AUX_MPU_RDP_REGION_SIZE(size) (((size - 1) & BIT_MASK(2)) | \
+ (((size - 1) & (BIT_MASK(3) << 2)) << 7))
+/* recover size from bit fields in RDP aux reg*/
+#define AUX_MPU_RDP_SIZE_SHIFT(rdp) ((rdp & BIT_MASK(2)) | (((rdp >> 9) & BIT_MASK(3)) << 2))
+
+#define AUX_MPU_RDB_VALID_MASK BIT(0)
+#define AUX_MPU_RDP_ATTR_MASK (BIT_MASK(6) << 3)
+#define AUX_MPU_RDP_SIZE_MASK ((BIT_MASK(3) << 9) | BIT_MASK(2))
+/* Global code cacheability that applies to a region
+ * 0x0: (Default) Code is cacheable in all levels of the cache hierarchy
+ * 0x1: Code is not cacheable in any level of the cache hierarchy
+ */
+#define AUX_MPU_RDB_IC BIT(12)
+/* Global data cacheability that applies to a region
+ * 0x0: (Default) Data is cacheable in all levels of the cache hierarchy
+ * 0x1: Data is not cacheable in any level of the cache hierarchy
+ */
+#define AUX_MPU_RDB_DC BIT(13)
+/* Define a MPU region as non-volatile
+ * 0x0: (Default) The memory space for this MPU region is treated as a volatile uncached space.
+ * 0x1: The memory space for this MPU region is non-volatile
+ */
+#define AUX_MPU_RDB_NV BIT(14)
+
+/* For MPU version 6, the minimum protection region size is 32 bytes */
+#define ARC_FEATURE_MPU_ALIGNMENT_BITS 5
+#define ARC_FEATURE_MPU_BANK_SIZE 16
+
+/**
+ * This internal function select a MPU bank
+ */
+static inline void _bank_select(uint32_t bank)
+{
+ uint32_t val;
+
+ val = z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & (~AUX_MPU_EN_BANK_MASK);
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN, val | bank);
+}
+/**
+ * This internal function initializes a MPU region
+ */
+static inline void _region_init(uint32_t index, uint32_t region_addr,
+ uint32_t size, uint32_t region_attr)
+{
+ uint32_t bank = index / ARC_FEATURE_MPU_BANK_SIZE;
+
+ index = (index % ARC_FEATURE_MPU_BANK_SIZE) * 2U;
+
+ if (size > 0) {
+ uint8_t bits = find_msb_set(size) - 1;
+
+ if (bits < ARC_FEATURE_MPU_ALIGNMENT_BITS) {
+ bits = ARC_FEATURE_MPU_ALIGNMENT_BITS;
+ }
+
+ if (BIT(bits) < size) {
+ bits++;
+ }
+
+ /* Clear size bits and IC, DC bits, and set NV bit
+ * The default value of NV bit is 0 which means the region is volatile and uncached.
+ * Setting the NV bit here has no effect on mpu v6 but is for the
+ * forward compatibility to mpu v7. Currently we do not allow to toggle these bits
+ * until we implement the control of these region properties
+ * TODO: support uncacheable regions and volatile uncached regions
+ */
+ region_attr &= ~(AUX_MPU_RDP_SIZE_MASK | AUX_MPU_RDB_IC | AUX_MPU_RDB_DC);
+ region_attr |= AUX_MPU_RDP_REGION_SIZE(bits) | AUX_MPU_RDB_NV;
+ region_addr |= AUX_MPU_RDB_VALID_MASK;
+ } else {
+ region_addr = 0U;
+ }
+
+ _bank_select(bank);
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_RDP0 + index, region_attr);
+ z_arc_v2_aux_reg_write(_ARC_V2_MPU_RDB0 + index, region_addr);
+}
+
+/**
+ * This internal function is utilized by the MPU driver to parse the intent
+ * type (i.e. THREAD_STACK_REGION) and return the correct region index.
+ */
+static inline int get_region_index_by_type(uint32_t type)
+{
+ /*
+ * The new MPU regions are allocated per type after the statically
+ * configured regions. The type is one-indexed rather than
+ * zero-indexed.
+ *
+ * For ARC MPU v6, the smaller index has higher priority, so the
+ * index is allocated in reverse order. Static regions start from
+ * the biggest index, then thread related regions.
+ *
+ */
+ switch (type) {
+ case THREAD_STACK_USER_REGION:
+ return get_num_regions() - mpu_config.num_regions - THREAD_STACK_REGION;
+ case THREAD_STACK_REGION:
+ case THREAD_APP_DATA_REGION:
+ case THREAD_DOMAIN_PARTITION_REGION:
+ /*
+ * Start domain partition region from stack guard region
+ * since stack guard is not supported.
+ */
+ return get_num_regions() - mpu_config.num_regions - type + 1;
+ default:
+ __ASSERT(0, "Unsupported type");
+ return -EINVAL;
+ }
+}
+
+/**
+ * This internal function checks if region is enabled or not
+ */
+static inline bool _is_enabled_region(uint32_t r_index)
+{
+ uint32_t bank = r_index / ARC_FEATURE_MPU_BANK_SIZE;
+ uint32_t index = (r_index % ARC_FEATURE_MPU_BANK_SIZE) * 2U;
+
+ _bank_select(bank);
+ return ((z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDB0 + index)
+ & AUX_MPU_RDB_VALID_MASK) == AUX_MPU_RDB_VALID_MASK);
+}
+
+/**
+ * This internal function check if the given buffer in in the region
+ */
+static inline bool _is_in_region(uint32_t r_index, uint32_t start, uint32_t size)
+{
+ uint32_t r_addr_start;
+ uint32_t r_addr_end;
+ uint32_t r_size_lshift;
+ uint32_t bank = r_index / ARC_FEATURE_MPU_BANK_SIZE;
+ uint32_t index = (r_index % ARC_FEATURE_MPU_BANK_SIZE) * 2U;
+
+ _bank_select(bank);
+ r_addr_start = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDB0 + index) & (~AUX_MPU_RDB_VALID_MASK);
+ r_size_lshift = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + index) & AUX_MPU_RDP_SIZE_MASK;
+ r_size_lshift = AUX_MPU_RDP_SIZE_SHIFT(r_size_lshift);
+ r_addr_end = r_addr_start + (1 << (r_size_lshift + 1));
+
+ if (start >= r_addr_start && (start + size) <= r_addr_end) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * This internal function check if the region is user accessible or not
+ */
+static inline bool _is_user_accessible_region(uint32_t r_index, int write)
+{
+ uint32_t r_ap;
+ uint32_t bank = r_index / ARC_FEATURE_MPU_BANK_SIZE;
+ uint32_t index = (r_index % ARC_FEATURE_MPU_BANK_SIZE) * 2U;
+
+ _bank_select(bank);
+ r_ap = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + index);
+
+ r_ap &= AUX_MPU_RDP_ATTR_MASK;
+
+ if (write) {
+ return ((r_ap & (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW)) ==
+ (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW));
+ }
+
+ return ((r_ap & (AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR)) ==
+ (AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR));
+}
+
+#endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V6_INTERNAL_H_ */
diff --git a/include/arch/arc/arch.h b/include/arch/arc/arch.h
index f576513..a7441f8 100644
--- a/include/arch/arc/arch.h
+++ b/include/arch/arc/arch.h
@@ -66,7 +66,7 @@
#ifdef CONFIG_ARC_CORE_MPU
#if CONFIG_ARC_MPU_VER == 2
#define Z_ARC_MPU_ALIGN 2048
-#elif (CONFIG_ARC_MPU_VER == 3) || (CONFIG_ARC_MPU_VER == 4)
+#elif (CONFIG_ARC_MPU_VER == 3) || (CONFIG_ARC_MPU_VER == 4) || (CONFIG_ARC_MPU_VER == 6)
#define Z_ARC_MPU_ALIGN 32
#else
#error "Unsupported MPU version"
diff --git a/include/arch/arc/v2/linker.ld b/include/arch/arc/v2/linker.ld
index 13245c7..89f3c96 100644
--- a/include/arch/arc/v2/linker.ld
+++ b/include/arch/arc/v2/linker.ld
@@ -30,7 +30,7 @@
#ifdef CONFIG_ARC_MPU_ENABLE
#if CONFIG_ARC_MPU_VER == 2
#define MPU_MIN_SIZE 2048
- #elif (CONFIG_ARC_MPU_VER == 3) || (CONFIG_ARC_MPU_VER == 4)
+ #elif (CONFIG_ARC_MPU_VER == 3) || (CONFIG_ARC_MPU_VER == 4) || (CONFIG_ARC_MPU_VER == 6)
#define MPU_MIN_SIZE 32
#endif
#define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE);