1 /*
2 * Copyright (c) 2019 Synopsys.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #ifndef ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
7 #define ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_
8
9 #define AUX_MPU_EN_ENABLE BIT(30)
10 #define AUX_MPU_EN_DISABLE ~BIT(30)
11
12 /*
13 * The size of the region is a 5-bit field, the three MSB bits are
14 * represented in [11:9] and the two LSB bits are represented in [1:0].
15 * Together these fields specify the size of the region in bytes:
16 * 00000-00011 Reserved
17 * 0x4 32 0x5 64 0x6 128 0x7 256
18 * 0x8 512 0x9 1k 0xA 2K 0xB 4K
19 * 0xC 8K 0xD 16K 0xE 32K 0xF 64K
20 * 0x10 128K 0x11 256K 0x12 512K 0x13 1M
21 * 0x14 2M 0x15 4M 0x16 8M 0x17 16M
22 * 0x18 32M 0x19 64M 0x1A 128M 0x1B 256M
23 * 0x1C 512M 0x1D 1G 0x1E 2G 0x1F 4G
24 *
25 * Bit ... 12 11 10 9 8 3 2 1 0
26 * ------+------------+------+---+-----------+
27 * ... | SIZE[11:9] | ATTR | R | SIZE[1:0] |
28 * ------+------------+------+---+-----------+
29 */
30 /* arrange size into proper bit field in RDP aux reg*/
31 #define AUX_MPU_RDP_REGION_SIZE(size) (((size - 1) & BIT_MASK(2)) | \
32 (((size - 1) & (BIT_MASK(3) << 2)) << 7))
33 /* recover size from bit fields in RDP aux reg*/
34 #define AUX_MPU_RDP_SIZE_SHIFT(rdp) ((rdp & BIT_MASK(2)) | (((rdp >> 9) & BIT_MASK(3)) << 2))
35
36 #define AUX_MPU_RDB_VALID_MASK BIT(0)
37 #define AUX_MPU_RDP_ATTR_MASK (BIT_MASK(6) << 3)
38 #define AUX_MPU_RDP_SIZE_MASK ((BIT_MASK(3) << 9) | BIT_MASK(2))
39
40 /* For MPU version 2, the minimum protection region size is 2048 bytes */
41 #if CONFIG_ARC_MPU_VER == 2
42 #define ARC_FEATURE_MPU_ALIGNMENT_BITS 11
43 /* For MPU version 3, the minimum protection region size is 32 bytes */
44 #else
45 #define ARC_FEATURE_MPU_ALIGNMENT_BITS 5
46 #endif
47
48 /**
49 * This internal function initializes a MPU region
50 */
_region_init(uint32_t index,uint32_t region_addr,uint32_t size,uint32_t region_attr)51 static inline void _region_init(uint32_t index, uint32_t region_addr, uint32_t size,
52 uint32_t region_attr)
53 {
54 index = index * 2U;
55
56 if (size > 0) {
57 uint8_t bits = find_msb_set(size) - 1;
58
59 if (bits < ARC_FEATURE_MPU_ALIGNMENT_BITS) {
60 bits = ARC_FEATURE_MPU_ALIGNMENT_BITS;
61 }
62
63 if (BIT(bits) < size) {
64 bits++;
65 }
66
67 region_attr &= ~(AUX_MPU_RDP_SIZE_MASK);
68 region_attr |= AUX_MPU_RDP_REGION_SIZE(bits);
69 region_addr |= AUX_MPU_RDB_VALID_MASK;
70 } else {
71 region_addr = 0U;
72 }
73
74 z_arc_v2_aux_reg_write(_ARC_V2_MPU_RDP0 + index, region_attr);
75 z_arc_v2_aux_reg_write(_ARC_V2_MPU_RDB0 + index, region_addr);
76 }
77
78 /**
79 * This internal function is utilized by the MPU driver to parse the intent
80 * type (i.e. THREAD_STACK_REGION) and return the correct region index.
81 */
get_region_index_by_type(uint32_t type)82 static inline int get_region_index_by_type(uint32_t type)
83 {
84 /*
85 * The new MPU regions are allocated per type after the statically
86 * configured regions. The type is one-indexed rather than
87 * zero-indexed.
88 *
89 * For ARC MPU v2, the smaller index has higher priority, so the
90 * index is allocated in reverse order. Static regions start from
91 * the biggest index, then thread related regions.
92 *
93 */
94 switch (type) {
95 case THREAD_STACK_USER_REGION:
96 return get_num_regions() - mpu_config.num_regions - THREAD_STACK_REGION;
97 case THREAD_STACK_REGION:
98 case THREAD_APP_DATA_REGION:
99 case THREAD_DOMAIN_PARTITION_REGION:
100 /*
101 * Start domain partition region from stack guard region
102 * since stack guard is not supported.
103 */
104 return get_num_regions() - mpu_config.num_regions - type + 1;
105 default:
106 __ASSERT(0, "Unsupported type");
107 return -EINVAL;
108 }
109 }
110
111 /**
112 * This internal function checks if region is enabled or not
113 */
_is_enabled_region(uint32_t r_index)114 static inline bool _is_enabled_region(uint32_t r_index)
115 {
116 return ((z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDB0 + r_index * 2U)
117 & AUX_MPU_RDB_VALID_MASK) == AUX_MPU_RDB_VALID_MASK);
118 }
119
120 /**
121 * This internal function check if the given buffer in in the region
122 */
_is_in_region(uint32_t r_index,uint32_t start,uint32_t size)123 static inline bool _is_in_region(uint32_t r_index, uint32_t start, uint32_t size)
124 {
125 uint32_t r_addr_start;
126 uint32_t r_addr_end;
127 uint32_t r_size_lshift;
128
129 r_addr_start = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDB0 + r_index * 2U)
130 & (~AUX_MPU_RDB_VALID_MASK);
131 r_size_lshift = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + r_index * 2U)
132 & AUX_MPU_RDP_SIZE_MASK;
133 r_size_lshift = AUX_MPU_RDP_SIZE_SHIFT(r_size_lshift);
134 r_addr_end = r_addr_start + (1 << (r_size_lshift + 1));
135
136 if (start >= r_addr_start && (start + size) <= r_addr_end) {
137 return true;
138 }
139
140 return false;
141 }
142
143 /**
144 * This internal function check if the region is user accessible or not
145 */
_is_user_accessible_region(uint32_t r_index,int write)146 static inline bool _is_user_accessible_region(uint32_t r_index, int write)
147 {
148 uint32_t r_ap;
149
150 r_ap = z_arc_v2_aux_reg_read(_ARC_V2_MPU_RDP0 + r_index * 2U);
151
152 r_ap &= AUX_MPU_RDP_ATTR_MASK;
153
154 if (write) {
155 return ((r_ap & (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW)) ==
156 (AUX_MPU_ATTR_UW | AUX_MPU_ATTR_KW));
157 }
158
159 return ((r_ap & (AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR)) ==
160 (AUX_MPU_ATTR_UR | AUX_MPU_ATTR_KR));
161 }
162
163 #endif /* ZEPHYR_ARCH_ARC_CORE_MPU_ARC_MPU_V2_INTERNAL_H_ */
164