1 /* SPDX-License-Identifier: Apache-2.0
2  *
3  * Copyright (c) 2019 Lexmark International, Inc.
4  */
5 
6 #include <zephyr/sys/math_extras.h>
7 
8 /**
9  *  Get the number of supported MPU regions.
10  */
get_num_regions(void)11 static inline uint8_t get_num_regions(void)
12 {
13 #if defined(NUM_MPU_REGIONS)
14 	/* Retrieve the number of regions from DTS configuration. */
15 	return NUM_MPU_REGIONS;
16 #else
17 	uint32_t type;
18 
19 	__asm__ volatile("mrc p15, 0, %0, c0, c0, 4" : "=r" (type) ::);
20 
21 	type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
22 
23 	return (uint8_t)type;
24 #endif /* NUM_MPU_REGIONS */
25 }
26 
get_region_attributes(void)27 static inline uint32_t get_region_attributes(void)
28 {
29 	uint32_t attr;
30 
31 	__asm__ volatile("mrc p15, 0, %0, c6, c1, 4" : "=r" (attr) ::);
32 	return attr;
33 }
34 
get_region_base_address(void)35 static inline uint32_t get_region_base_address(void)
36 {
37 	uint32_t addr;
38 
39 	__asm__ volatile("mrc p15, 0, %0, c6, c1, 0" : "=r" (addr) ::);
40 	return addr;
41 }
42 
get_region_size(void)43 static inline uint32_t get_region_size(void)
44 {
45 	uint32_t size;
46 
47 	__asm__ volatile("mrc p15, 0, %0, c6, c1, 2" : "=r" (size) ::);
48 	return size;
49 }
50 
set_region_attributes(uint32_t attr)51 static inline void set_region_attributes(uint32_t attr)
52 {
53 	__asm__ volatile("mcr p15, 0, %0, c6, c1, 4" :: "r" (attr) :);
54 }
55 
set_region_base_address(uint32_t addr)56 static inline void set_region_base_address(uint32_t addr)
57 {
58 	__asm__ volatile("mcr p15, 0, %0, c6, c1, 0" :: "r" (addr) :);
59 }
60 
set_region_number(uint32_t index)61 static inline void set_region_number(uint32_t index)
62 {
63 	__asm__ volatile("mcr p15, 0, %0, c6, c2, 0" :: "r" (index) :);
64 }
65 
mpu_region_get_base(uint32_t index)66 static inline uint32_t mpu_region_get_base(uint32_t index)
67 {
68 	set_region_number(index);
69 
70 	return get_region_base_address() & MPU_RBAR_ADDR_Msk;
71 }
72 
73 /**
74  * This internal function converts the SIZE field value of MPU_RASR
75  * to the region size (in bytes).
76  */
mpu_rasr_size_to_size(uint32_t rasr_size)77 static inline uint32_t mpu_rasr_size_to_size(uint32_t rasr_size)
78 {
79 	return 1 << (rasr_size + 1U);
80 }
81 
set_region_size(uint32_t size)82 static inline void set_region_size(uint32_t size)
83 {
84 	__asm__ volatile("mcr p15, 0, %0, c6, c1, 2" :: "r" (size) :);
85 }
86 
ARM_MPU_ClrRegion(uint32_t rnr)87 static inline void ARM_MPU_ClrRegion(uint32_t rnr)
88 {
89 	set_region_number(rnr);
90 	/* clear size field, which contains enable bit */
91 	set_region_size(0);
92 }
93 
94 /**
95  * This internal function checks if region is enabled or not.
96  *
97  * Note:
98  *   The caller must provide a valid region number.
99  */
is_enabled_region(uint32_t index)100 static inline int is_enabled_region(uint32_t index)
101 {
102 	set_region_number(index);
103 
104 	return (get_region_size() & MPU_RASR_ENABLE_Msk) ? 1 : 0;
105 }
106 
107 /**
108  * This internal function returns the access permissions of an MPU region
109  * specified by its region index.
110  *
111  * Note:
112  *   The caller must provide a valid region number.
113  */
get_region_ap(uint32_t r_index)114 static inline uint32_t get_region_ap(uint32_t r_index)
115 {
116 	set_region_number(r_index);
117 
118 	return (get_region_attributes() & MPU_RASR_AP_Msk) >> MPU_RASR_AP_Pos;
119 }
120 
121 /**
122  * This internal function checks if the given buffer is in the region.
123  *
124  * Note:
125  *   The caller must provide a valid region number.
126  */
is_in_region(uint32_t r_index,uint32_t start,uint32_t size)127 static inline int is_in_region(uint32_t r_index, uint32_t start, uint32_t size)
128 {
129 	uint32_t r_addr_start;
130 	uint32_t r_size_lshift;
131 	uint32_t r_addr_end;
132 	uint32_t end;
133 
134 	set_region_number(r_index);
135 
136 	r_addr_start = get_region_base_address() & MPU_RBAR_ADDR_Msk;
137 
138 	r_size_lshift = ((get_region_size() & MPU_RASR_SIZE_Msk) >>
139 		MPU_RASR_SIZE_Pos) + 1;
140 
141 	r_addr_end = r_addr_start + (1UL << r_size_lshift) - 1;
142 
143 	size = size == 0 ? 0 : size - 1;
144 	if (u32_add_overflow(start, size, &end)) {
145 		return 0;
146 	}
147 
148 	if ((start >= r_addr_start) && (end <= r_addr_end)) {
149 		return 1;
150 	}
151 
152 	return 0;
153 }
154 
mpu_region_get_size(uint32_t index)155 static inline uint32_t mpu_region_get_size(uint32_t index)
156 {
157 	set_region_number(index);
158 
159 	uint32_t rasr_size =
160 		(get_region_size() & MPU_RASR_SIZE_Msk) >> MPU_RASR_SIZE_Pos;
161 
162 	return mpu_rasr_size_to_size(rasr_size);
163 }
164