Skip to content

Commit eb14e21

Browse files
YuguoWHnashif
authored andcommitted
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 <[email protected]>
1 parent 333501e commit eb14e21

File tree

7 files changed

+536
-314
lines changed

7 files changed

+536
-314
lines changed

arch/arc/core/mpu/Kconfig

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55

66
config ARC_MPU_VER
77
int "ARC MPU version"
8-
range 2 4
8+
range 2 6
99
default 2
1010
help
1111
ARC MPU has several versions. For MPU v2, the minimum region is 2048 bytes;
12-
For MPU v3 and v4, the minimum region is 32 bytes
12+
For other versions, the minimum region is 32 bytes; v4 has secure features,
13+
v6 supports up to 32 regions.
1314

1415
config ARC_CORE_MPU
1516
bool "ARC Core MPU functionalities"
@@ -31,8 +32,8 @@ config ARC_MPU
3132
select SRAM_REGION_PERMISSIONS
3233
select ARC_CORE_MPU
3334
select THREAD_STACK_INFO
34-
select GEN_PRIV_STACKS if ARC_MPU_VER = 2
35-
select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if ARC_MPU_VER = 2
35+
select GEN_PRIV_STACKS if ARC_MPU_VER != 4
36+
select MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT if ARC_MPU_VER !=4
3637
select MPU_REQUIRES_NON_OVERLAPPING_REGIONS if ARC_MPU_VER = 4
3738
help
3839
Target has ARC MPU (currently only works for EMSK 2.2/2.3 ARCEM7D)

arch/arc/core/mpu/arc_mpu.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ static inline uint32_t get_region_attr_by_type(uint32_t type)
5252
}
5353
}
5454

55-
#if CONFIG_ARC_MPU_VER == 2
56-
#include "arc_mpu_v2_internal.h"
57-
#elif CONFIG_ARC_MPU_VER == 4
55+
#if CONFIG_ARC_MPU_VER == 4
5856
#include "arc_mpu_v4_internal.h"
57+
#else
58+
#include "arc_mpu_common_internal.h"
5959
#endif
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
/*
2+
* Copyright (c) 2021 Synopsys.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_
7+
#define ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_
8+
9+
#if CONFIG_ARC_MPU_VER == 2 || CONFIG_ARC_MPU_VER == 3
10+
#include "arc_mpu_v2_internal.h"
11+
#elif CONFIG_ARC_MPU_VER == 6
12+
#include "arc_mpu_v6_internal.h"
13+
#else
14+
#error "Unsupported MPU version"
15+
#endif
16+
17+
/**
18+
* @brief configure the base address and size for an MPU region
19+
*
20+
* @param type MPU region type
21+
* @param base base address in RAM
22+
* @param size size of the region
23+
*/
24+
static inline int _mpu_configure(uint8_t type, uint32_t base, uint32_t size)
25+
{
26+
int32_t region_index = get_region_index_by_type(type);
27+
uint32_t region_attr = get_region_attr_by_type(type);
28+
29+
LOG_DBG("Region info: 0x%x 0x%x", base, size);
30+
31+
if (region_attr == 0U || region_index < 0) {
32+
return -EINVAL;
33+
}
34+
35+
/*
36+
* For ARC MPU, MPU regions can be overlapped, smaller
37+
* region index has higher priority.
38+
*/
39+
_region_init(region_index, base, size, region_attr);
40+
41+
return 0;
42+
}
43+
44+
/* ARC Core MPU Driver API Implementation for ARC MP */
45+
46+
/**
47+
* @brief enable the MPU
48+
*/
49+
void arc_core_mpu_enable(void)
50+
{
51+
/* Enable MPU */
52+
z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
53+
z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) | AUX_MPU_EN_ENABLE);
54+
}
55+
56+
/**
57+
* @brief disable the MPU
58+
*/
59+
void arc_core_mpu_disable(void)
60+
{
61+
/* Disable MPU */
62+
z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN,
63+
z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & AUX_MPU_EN_DISABLE);
64+
}
65+
66+
/**
67+
* @brief configure the thread's MPU regions
68+
*
69+
* @param thread the target thread
70+
*/
71+
void arc_core_mpu_configure_thread(struct k_thread *thread)
72+
{
73+
#if defined(CONFIG_USERSPACE)
74+
/* configure stack region of user thread */
75+
if (thread->base.user_options & K_USER) {
76+
LOG_DBG("configure user thread %p's stack", thread);
77+
if (_mpu_configure(THREAD_STACK_USER_REGION,
78+
(uint32_t)thread->stack_info.start,
79+
thread->stack_info.size) < 0) {
80+
LOG_ERR("user thread %p's stack failed", thread);
81+
return;
82+
}
83+
}
84+
85+
LOG_DBG("configure thread %p's domain", thread);
86+
arc_core_mpu_configure_mem_domain(thread);
87+
#endif
88+
}
89+
90+
91+
/**
92+
* @brief configure the default region
93+
*
94+
* @param region_attr region attribute of default region
95+
*/
96+
void arc_core_mpu_default(uint32_t region_attr)
97+
{
98+
uint32_t val = z_arc_v2_aux_reg_read(_ARC_V2_MPU_EN) & (~AUX_MPU_RDP_ATTR_MASK);
99+
100+
region_attr &= AUX_MPU_RDP_ATTR_MASK;
101+
z_arc_v2_aux_reg_write(_ARC_V2_MPU_EN, region_attr | val);
102+
}
103+
104+
/**
105+
* @brief configure the MPU region
106+
*
107+
* @param index MPU region index
108+
* @param base base address
109+
* @param region_attr region attribute
110+
*/
111+
int arc_core_mpu_region(uint32_t index, uint32_t base, uint32_t size, uint32_t region_attr)
112+
{
113+
if (index >= get_num_regions()) {
114+
return -EINVAL;
115+
}
116+
117+
region_attr &= AUX_MPU_RDP_ATTR_MASK;
118+
119+
_region_init(index, base, size, region_attr);
120+
121+
return 0;
122+
}
123+
124+
#if defined(CONFIG_USERSPACE)
125+
126+
/**
127+
* @brief configure MPU regions for the memory partitions of the memory domain
128+
*
129+
* @param thread the thread which has memory domain
130+
*/
131+
void arc_core_mpu_configure_mem_domain(struct k_thread *thread)
132+
{
133+
int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
134+
uint32_t num_partitions;
135+
struct k_mem_partition *pparts;
136+
struct k_mem_domain *mem_domain = NULL;
137+
138+
if (thread) {
139+
mem_domain = thread->mem_domain_info.mem_domain;
140+
}
141+
142+
if (mem_domain) {
143+
LOG_DBG("configure domain: %p", mem_domain);
144+
num_partitions = mem_domain->num_partitions;
145+
pparts = mem_domain->partitions;
146+
} else {
147+
LOG_DBG("disable domain partition regions");
148+
num_partitions = 0U;
149+
pparts = NULL;
150+
}
151+
152+
for (; region_index >= 0; region_index--) {
153+
if (num_partitions) {
154+
LOG_DBG("set region 0x%x 0x%lx 0x%x",
155+
region_index, pparts->start, pparts->size);
156+
_region_init(region_index, pparts->start, pparts->size, pparts->attr);
157+
num_partitions--;
158+
} else {
159+
/* clear the left mpu entries */
160+
_region_init(region_index, 0, 0, 0);
161+
}
162+
pparts++;
163+
}
164+
}
165+
166+
/**
167+
* @brief remove MPU regions for the memory partitions of the memory domain
168+
*
169+
* @param mem_domain the target memory domain
170+
*/
171+
void arc_core_mpu_remove_mem_domain(struct k_mem_domain *mem_domain)
172+
{
173+
ARG_UNUSED(mem_domain);
174+
175+
int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
176+
177+
for (; region_index >= 0; region_index--) {
178+
_region_init(region_index, 0, 0, 0);
179+
}
180+
}
181+
182+
/**
183+
* @brief reset MPU region for a single memory partition
184+
*
185+
* @param domain the target memory domain
186+
* @param partition_id memory partition id
187+
*/
188+
void arc_core_mpu_remove_mem_partition(struct k_mem_domain *domain, uint32_t part_id)
189+
{
190+
ARG_UNUSED(domain);
191+
192+
int region_index = get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION);
193+
194+
LOG_DBG("disable region 0x%x", region_index + part_id);
195+
/* Disable region */
196+
_region_init(region_index + part_id, 0, 0, 0);
197+
}
198+
199+
/**
200+
* @brief get the maximum number of free regions for memory domain partitions
201+
*/
202+
int arc_core_mpu_get_max_domain_partition_regions(void)
203+
{
204+
return get_region_index_by_type(THREAD_DOMAIN_PARTITION_REGION) + 1;
205+
}
206+
207+
/**
208+
* @brief validate the given buffer is user accessible or not
209+
*/
210+
int arc_core_mpu_buffer_validate(void *addr, size_t size, int write)
211+
{
212+
/*
213+
* For ARC MPU, smaller region number takes priority.
214+
* we can stop the iteration immediately once we find the
215+
* matched region that grants permission or denies access.
216+
*
217+
*/
218+
for (int r_index = 0; r_index < get_num_regions(); r_index++) {
219+
if (!_is_enabled_region(r_index) || !_is_in_region(r_index, (uint32_t)addr, size)) {
220+
continue;
221+
}
222+
223+
if (_is_user_accessible_region(r_index, write)) {
224+
return 0;
225+
} else {
226+
return -EPERM;
227+
}
228+
}
229+
230+
return -EPERM;
231+
}
232+
#endif /* CONFIG_USERSPACE */
233+
234+
/* ARC MPU Driver Initial Setup */
235+
/*
236+
* @brief MPU default initialization and configuration
237+
*
238+
* This function provides the default configuration mechanism for the Memory
239+
* Protection Unit (MPU).
240+
*/
241+
static int arc_mpu_init(const struct device *arg)
242+
{
243+
ARG_UNUSED(arg);
244+
245+
uint32_t num_regions = get_num_regions();
246+
247+
if (mpu_config.num_regions > num_regions) {
248+
__ASSERT(0, "Request to configure: %u regions (supported: %u)\n",
249+
mpu_config.num_regions, num_regions);
250+
return -EINVAL;
251+
}
252+
253+
/* Disable MPU */
254+
arc_core_mpu_disable();
255+
256+
/*
257+
* the MPU regions are filled in the reverse order.
258+
* According to ARCv2 ISA, the MPU region with smaller
259+
* index has higher priority. The static background MPU
260+
* regions in mpu_config will be in the bottom. Then
261+
* the special type regions will be above.
262+
*/
263+
int r_index = num_regions - mpu_config.num_regions;
264+
265+
/* clear all the regions first */
266+
for (uint32_t i = 0U; i < r_index; i++) {
267+
_region_init(i, 0, 0, 0);
268+
}
269+
270+
/* configure the static regions */
271+
for (uint32_t i = 0U; i < mpu_config.num_regions; i++) {
272+
_region_init(r_index, mpu_config.mpu_regions[i].base,
273+
mpu_config.mpu_regions[i].size, mpu_config.mpu_regions[i].attr);
274+
r_index++;
275+
}
276+
277+
/* default region: no read, write and execute */
278+
arc_core_mpu_default(0);
279+
280+
/* Enable MPU */
281+
arc_core_mpu_enable();
282+
283+
return 0;
284+
}
285+
286+
SYS_INIT(arc_mpu_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
287+
288+
#endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_COMMON_INTERNAL_H_ */

0 commit comments

Comments
 (0)