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