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