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>
This commit is contained in:
parent
333501e871
commit
eb14e21d18
7 changed files with 536 additions and 314 deletions
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
config ARC_MPU_VER
|
config ARC_MPU_VER
|
||||||
int "ARC MPU version"
|
int "ARC MPU version"
|
||||||
range 2 4
|
range 2 6
|
||||||
default 2
|
default 2
|
||||||
help
|
help
|
||||||
ARC MPU has several versions. For MPU v2, the minimum region is 2048 bytes;
|
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
|
config ARC_CORE_MPU
|
||||||
bool "ARC Core MPU functionalities"
|
bool "ARC Core MPU functionalities"
|
||||||
|
@ -31,8 +32,8 @@ config ARC_MPU
|
||||||
select SRAM_REGION_PERMISSIONS
|
select SRAM_REGION_PERMISSIONS
|
||||||
select ARC_CORE_MPU
|
select ARC_CORE_MPU
|
||||||
select THREAD_STACK_INFO
|
select THREAD_STACK_INFO
|
||||||
select GEN_PRIV_STACKS 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 = 2
|
select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if ARC_MPU_VER !=4
|
||||||
select MPU_REQUIRES_NON_OVERLAPPING_REGIONS if ARC_MPU_VER = 4
|
select MPU_REQUIRES_NON_OVERLAPPING_REGIONS if ARC_MPU_VER = 4
|
||||||
help
|
help
|
||||||
Target has ARC MPU (currently only works for EMSK 2.2/2.3 ARCEM7D)
|
Target has ARC MPU (currently only works for EMSK 2.2/2.3 ARCEM7D)
|
||||||
|
|
|
@ -52,8 +52,8 @@ static inline uint32_t get_region_attr_by_type(uint32_t type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_ARC_MPU_VER == 2
|
#if CONFIG_ARC_MPU_VER == 4
|
||||||
#include "arc_mpu_v2_internal.h"
|
|
||||||
#elif CONFIG_ARC_MPU_VER == 4
|
|
||||||
#include "arc_mpu_v4_internal.h"
|
#include "arc_mpu_v4_internal.h"
|
||||||
|
#else
|
||||||
|
#include "arc_mpu_common_internal.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
288
arch/arc/core/mpu/arc_mpu_common_internal.h
Normal file
288
arch/arc/core/mpu/arc_mpu_common_internal.h
Normal file
|
@ -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_ */
|
|
@ -6,15 +6,36 @@
|
||||||
#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
|
#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
|
||||||
#define 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 BIT(30)
|
||||||
#define AUX_MPU_EN_ENABLE (0x40000000)
|
#define AUX_MPU_EN_DISABLE ~BIT(30)
|
||||||
#define AUX_MPU_EN_DISABLE (0xBFFFFFFF)
|
|
||||||
|
|
||||||
#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_RDB_VALID_MASK BIT(0)
|
||||||
#define AUX_MPU_RDP_SIZE_MASK (0xE03)
|
#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 */
|
/* For MPU version 2, the minimum protection region size is 2048 bytes */
|
||||||
#if CONFIG_ARC_MPU_VER == 2
|
#if CONFIG_ARC_MPU_VER == 2
|
||||||
|
@ -39,7 +60,7 @@ static inline void _region_init(uint32_t index, uint32_t region_addr, uint32_t s
|
||||||
bits = ARC_FEATURE_MPU_ALIGNMENT_BITS;
|
bits = ARC_FEATURE_MPU_ALIGNMENT_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((1 << bits) < size) {
|
if (BIT(bits) < size) {
|
||||||
bits++;
|
bits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +93,7 @@ static inline int get_region_index_by_type(uint32_t type)
|
||||||
*/
|
*/
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case THREAD_STACK_USER_REGION:
|
case THREAD_STACK_USER_REGION:
|
||||||
return get_num_regions() - mpu_config.num_regions
|
return get_num_regions() - mpu_config.num_regions - THREAD_STACK_REGION;
|
||||||
- THREAD_STACK_REGION;
|
|
||||||
case THREAD_STACK_REGION:
|
case THREAD_STACK_REGION:
|
||||||
case THREAD_APP_DATA_REGION:
|
case THREAD_APP_DATA_REGION:
|
||||||
case THREAD_DOMAIN_PARTITION_REGION:
|
case THREAD_DOMAIN_PARTITION_REGION:
|
||||||
|
@ -110,14 +130,14 @@ static inline bool _is_in_region(uint32_t r_index, uint32_t start, uint32_t size
|
||||||
& (~AUX_MPU_RDB_VALID_MASK);
|
& (~AUX_MPU_RDB_VALID_MASK);
|
||||||
r_size_lshift = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + r_index * 2U)
|
r_size_lshift = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + r_index * 2U)
|
||||||
& AUX_MPU_RDP_SIZE_MASK;
|
& 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));
|
r_addr_end = r_addr_start + (1 << (r_size_lshift + 1));
|
||||||
|
|
||||||
if (start >= r_addr_start && (start + size) <= r_addr_end) {
|
if (start >= r_addr_start && (start + size) <= r_addr_end) {
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,296 +160,4 @@ static inline bool _is_user_accessible_region(uint32_t r_index, int write)
|
||||||
(AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR));
|
(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_ */
|
#endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_ */
|
||||||
|
|
205
arch/arc/core/mpu/arc_mpu_v6_internal.h
Normal file
205
arch/arc/core/mpu/arc_mpu_v6_internal.h
Normal file
|
@ -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_ */
|
|
@ -66,7 +66,7 @@ extern "C" {
|
||||||
#ifdef CONFIG_ARC_CORE_MPU
|
#ifdef CONFIG_ARC_CORE_MPU
|
||||||
#if CONFIG_ARC_MPU_VER == 2
|
#if CONFIG_ARC_MPU_VER == 2
|
||||||
#define Z_ARC_MPU_ALIGN 2048
|
#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
|
#define Z_ARC_MPU_ALIGN 32
|
||||||
#else
|
#else
|
||||||
#error "Unsupported MPU version"
|
#error "Unsupported MPU version"
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#ifdef CONFIG_ARC_MPU_ENABLE
|
#ifdef CONFIG_ARC_MPU_ENABLE
|
||||||
#if CONFIG_ARC_MPU_VER == 2
|
#if CONFIG_ARC_MPU_VER == 2
|
||||||
#define MPU_MIN_SIZE 2048
|
#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
|
#define MPU_MIN_SIZE 32
|
||||||
#endif
|
#endif
|
||||||
#define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE);
|
#define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue