RTEMS 6.1-rc6
Loading...
Searching...
No Matches
armv7-pmsa.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-2-Clause */
2
12/*
13 * Copyright (C) 2024 embedded brains GmbH & Co. KG
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#ifndef _RTEMS_SCORE_ARMV7_PMSA_H
38#define _RTEMS_SCORE_ARMV7_PMSA_H
39
41#include <rtems/score/assert.h>
42#include <rtems/score/cpu.h>
43
44#ifdef __cplusplus
45extern "C" {
46#endif
47
48/*
49 * Allow users of this header file to optionally place the inline functions
50 * into a non-standard section.
51 */
52#ifndef ARMV7_PMSA_TEXT_SECTION
53#define ARMV7_PMSA_TEXT_SECTION
54#endif
55
67/* RGNR, MPU Region Number Register */
68
69#define ARMV7_RGNR_REGION_SHIFT 0
70#define ARMV7_RGNR_REGION_MASK 0xffU
71#define ARMV7_RGNR_REGION_GET(_reg) \
72 (((_reg)&ARMV7_RGNR_REGION_MASK) >> ARMV7_RGNR_REGION_SHIFT)
73#define ARMV7_RGNR_REGION_SET(_reg, _val) \
74 (((_reg) & ~ARMV7_RGNR_REGION_MASK) | \
75 (((_val) << ARMV7_RGNR_REGION_SHIFT) & ARMV7_RGNR_REGION_MASK))
76#define ARMV7_RGNR_REGION(_val) \
77 (((_val) << ARMV7_RGNR_REGION_SHIFT) & ARMV7_RGNR_REGION_MASK)
78
79static inline uint32_t _ARMV7_Read_rgnr(void) {
80 uint32_t value;
81
82 __asm__ volatile("mrc p15, 0, %0, c6, c2, 0" : "=&r"(value) : : "memory");
83
84 return value;
85}
86
87static inline void _ARMV7_Write_rgnr(uint32_t value) {
88 __asm__ volatile("mcr p15, 0, %0, c6, c2, 0" : : "r"(value) : "memory");
89}
90
91/* DRBAR, Data Region Base Address Register */
92
93static inline uint32_t _ARMV7_Read_drbar(void) {
94 uint32_t value;
95
96 __asm__ volatile("mrc p15, 0, %0, c6, c1, 0" : "=&r"(value) : : "memory");
97
98 return value;
99}
100
101static inline void _ARMV7_Write_drbar(uint32_t value) {
102 __asm__ volatile("mcr p15, 0, %0, c6, c1, 0" : : "r"(value) : "memory");
103}
104
105/* IRBAR, Instruction Region Base Address Register */
106
107static inline uint32_t _ARMV7_Read_irbar(void) {
108 uint32_t value;
109
110 __asm__ volatile("mrc p15, 0, %0, c6, c1, 1" : "=&r"(value) : : "memory");
111
112 return value;
113}
114
115static inline void _ARMV7_Write_irbar(uint32_t value) {
116 __asm__ volatile("mcr p15, 0, %0, c6, c1, 1" : : "r"(value) : "memory");
117}
118
119#define ARMV7_RSR_EN 0x1U
120
121#define ARMV7_RSR_RSIZE_SHIFT 1
122#define ARMV7_RSR_RSIZE_MASK 0x3eU
123#define ARMV7_RSR_RSIZE_GET(_reg) \
124 (((_reg)&ARMV7_RSR_RSIZE_MASK) >> ARMV7_RSR_RSIZE_SHIFT)
125#define ARMV7_RSR_RSIZE_SET(_reg, _val) \
126 (((_reg) & ~ARMV7_RSR_RSIZE_MASK) | \
127 (((_val) << ARMV7_RSR_RSIZE_SHIFT) & ARMV7_RSR_RSIZE_MASK))
128#define ARMV7_RSR_RSIZE(_val) \
129 (((_val) << ARMV7_RSR_RSIZE_SHIFT) & ARMV7_RSR_RSIZE_MASK)
130
131#define ARMV7_RSR_SD_SHIFT 8
132#define ARMV7_RSR_SD_MASK 0xff00U
133#define ARMV7_RSR_SD_GET(_reg) \
134 (((_reg)&ARMV7_RSR_SD_MASK) >> ARMV7_RSR_SD_SHIFT)
135#define ARMV7_RSR_SD_SET(_reg, _val) \
136 (((_reg) & ~ARMV7_RSR_SD_MASK) | \
137 (((_val) << ARMV7_RSR_SD_SHIFT) & ARMV7_RSR_SD_MASK))
138#define ARMV7_RSR_SD(_val) (((_val) << ARMV7_RSR_SD_SHIFT) & ARMV7_RSR_SD_MASK)
139
140/* DRSR, Data Region Size and Enable Register */
141
142static inline uint32_t _ARMV7_Read_drsr(void) {
143 uint32_t value;
144
145 __asm__ volatile("mrc p15, 0, %0, c6, c1, 2" : "=&r"(value) : : "memory");
146
147 return value;
148}
149
150static inline void _ARMV7_Write_drsr(uint32_t value) {
151 __asm__ volatile("mcr p15, 0, %0, c6, c1, 2" : : "r"(value) : "memory");
152}
153
154/* IRSR, Instruction Region Size and Enable Register */
155
156static inline uint32_t _ARMV7_Read_irsr(void) {
157 uint32_t value;
158
159 __asm__ volatile("mrc p15, 0, %0, c6, c1, 3" : "=&r"(value) : : "memory");
160
161 return value;
162}
163
164static inline void _ARMV7_Write_irsr(uint32_t value) {
165 __asm__ volatile("mcr p15, 0, %0, c6, c1, 3" : : "r"(value) : "memory");
166}
167
168#define ARMV7_RACR_B 0x1U
169#define ARMV7_RACR_C 0x2U
170#define ARMV7_RACR_S 0x4U
171#define ARMV7_RACR_TEX_0 0x8U
172#define ARMV7_RACR_TEX_1 0x10U
173#define ARMV7_RACR_TEX_2 0x20U
174#define ARMV7_RACR_AP_0 0x100U
175#define ARMV7_RACR_AP_1 0x200U
176#define ARMV7_RACR_AP_2 0x400U
177#define ARMV7_RACR_XN 0x1000U
178
179/* DRACR, Data Region Access Control Register */
180
181static inline uint32_t _ARMV7_Read_dracr(void) {
182 uint32_t value;
183
184 __asm__ volatile("mrc p15, 0, %0, c6, c1, 4" : "=&r"(value) : : "memory");
185
186 return value;
187}
188
189static inline void _ARMV7_Write_dracr(uint32_t value) {
190 __asm__ volatile("mcr p15, 0, %0, c6, c1, 4" : : "r"(value) : "memory");
191}
192
193/* IRACR, Instruction Region Access Control Register */
194
195static inline uint32_t _ARMV7_Read_iracr(void) {
196 uint32_t value;
197
198 __asm__ volatile("mrc p15, 0, %0, c6, c1, 5" : "=&r"(value) : : "memory");
199
200 return value;
201}
202
203static inline void _ARMV7_Write_iracr(uint32_t value) {
204 __asm__ volatile("mcr p15, 0, %0, c6, c1, 5" : : "r"(value) : "memory");
205}
206
207#define ARMV7_PMSA_READ_ONLY_CACHED \
208 (ARMV7_RACR_TEX_0 | ARMV7_RACR_C | ARMV7_RACR_B | ARMV7_RACR_AP_0 | \
209 ARMV7_RACR_AP_2)
210
211#define ARMV7_PMSA_READ_ONLY_UNCACHED \
212 (ARMV7_RACR_TEX_0 | ARMV7_RACR_AP_0 | ARMV7_RACR_AP_2)
213
214#define ARMV7_PMSA_READ_WRITE_CACHED \
215 (ARMV7_RACR_TEX_0 | ARMV7_RACR_C | ARMV7_RACR_B | ARMV7_RACR_AP_0)
216
217#define ARMV7_PMSA_READ_WRITE_UNCACHED (ARMV7_RACR_TEX_0 | ARMV7_RACR_AP_0)
218
219#define ARMV7_PMSA_READ_WRITE_SHARED \
220 (ARMV7_RACR_TEX_0 | ARMV7_RACR_S | ARMV7_RACR_AP_0)
221
222#define ARMV7_PMSA_SHAREABLE_DEVICE (ARMV7_RACR_B | ARMV7_RACR_AP_0)
223
224#define ARMV7_PMSA_NON_SHAREABLE_DEVICE (ARMV7_RACR_TEX_1 | ARMV7_RACR_AP_0)
225
232typedef struct ARMV7_PMSA_Region {
236 uint32_t begin;
237
241 uint32_t size;
242
246 uint32_t attributes;
248
249ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Power2(uint32_t x) {
250 return 32 - __builtin_clz(x - 1U);
251}
252
253ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Ceil2(uint32_t x) {
254 return 1U << _ARMV7_PMSA_Power2(x);
255}
256
257ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Down2(uint32_t x,
258 uint32_t y) {
259 uint32_t m = y - 1U;
260 return x & ~m;
261}
262
263ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Up2(uint32_t x,
264 uint32_t y) {
265 uint32_t m = y - 1U;
266 return (x + m) & ~m;
267}
268
269ARMV7_PMSA_TEXT_SECTION static inline uint32_t
270_ARMV7_PMSA_Get_region(uint32_t b, uint32_t s, uint32_t* rs) {
271 uint32_t e = b + s;
272 uint32_t s2 = _ARMV7_PMSA_Ceil2(s);
273 uint32_t b2 = _ARMV7_PMSA_Down2(b, s2);
274 uint32_t e2 = _ARMV7_PMSA_Up2(e, s2);
275 uint32_t s3 = _ARMV7_PMSA_Ceil2(e2 - b2);
276 *rs = s3;
277 return _ARMV7_PMSA_Down2(b2, s3);
278}
279
280ARMV7_PMSA_TEXT_SECTION static inline void _ARMV7_PMSA_Write_region(
281 uint32_t index,
282 uint32_t b,
283 uint32_t s,
284 uint32_t rb,
285 uint32_t rs,
286 uint32_t attr) {
287 int rp = _ARMV7_PMSA_Power2(rs);
288 int shift = rp - 3;
289 uint32_t u = (b - rb) >> shift;
290 uint32_t v = (_ARMV7_PMSA_Up2(b + s, 1U << shift) - rb) >> shift;
291 uint32_t sub = ((0xffU >> (8 - v)) >> u) << u;
292
293 _ARMV7_Write_rgnr(ARMV7_RGNR_REGION(index));
294 _ARM_Instruction_synchronization_barrier();
295 _ARMV7_Write_drbar(rb);
296 _ARMV7_Write_dracr(attr);
297 _ARMV7_Write_drsr(ARMV7_RSR_SD(~sub) | ARMV7_RSR_RSIZE(rp - 1) |
298 ARMV7_RSR_EN);
299 _ARM_Data_synchronization_barrier();
300 _ARM_Instruction_synchronization_barrier();
301}
302
303ARMV7_PMSA_TEXT_SECTION static inline uint32_t
304_ARMV7_PMSA_Add_regions(uint32_t index, uint32_t b, uint32_t s, uint32_t attr) {
305 uint32_t rs;
306 uint32_t rb = _ARMV7_PMSA_Get_region(b, s, &rs);
307 uint32_t e = b + s;
308
309 if (e - rb > rs) {
310 uint32_t re = rb + rs;
311 uint32_t bl = b;
312 uint32_t sl = re - b;
313
314 rb = _ARMV7_PMSA_Get_region(bl, sl, &rs);
315 _ARMV7_PMSA_Write_region(index, bl, sl, rb, rs, attr);
316 ++index;
317
318 s = e - re;
319 b = re;
320 rb = _ARMV7_PMSA_Get_region(b, s, &rs);
321 }
322
323 _ARMV7_PMSA_Write_region(index, b, s, rb, rs, attr);
324 return index + 1;
325}
326
327ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Get_max_regions(
328 void
329)
330{
331 uint32_t region_count = _AArch32_Read_mpuir();
332
333 region_count &= AARCH32_MPUIR_REGION_MASK;
334 region_count >>= AARCH32_MPUIR_REGION_SHIFT;
335
336 return region_count;
337}
338
339ARMV7_PMSA_TEXT_SECTION static inline uint32_t _ARMV7_PMSA_Find_region(
340 uintptr_t address,
341 uint32_t index) {
342 uint32_t region_count = _ARMV7_PMSA_Get_max_regions();
343
344 while (index < region_count) {
345 _ARMV7_Write_rgnr(ARMV7_RGNR_REGION(index));
346 _ARM_Instruction_synchronization_barrier();
347
348 uint32_t rsr = _ARMV7_Read_drsr();
349
350 if ((rsr & ARMV7_RSR_EN) != 0) {
351 uint32_t rbar = _ARMV7_Read_drbar();
352 uint32_t offset = (address & ~UINT32_C(0x3)) - rbar;
353 uint32_t region_power = ARMV7_RSR_RSIZE_GET(rsr) + 1;
354 uint32_t region_size = UINT32_C(1) << region_power;
355
356 if (offset < region_size) {
357 if (region_size < 256) {
358 return index;
359 }
360
361 uint32_t sub = offset >> (region_power - 3);
362
363 if ((ARMV7_RSR_SD_GET(rsr) & (UINT32_C(1) << sub)) == 0) {
364 return index;
365 }
366 }
367 }
368
369 ++index;
370 }
371
372 return UINT32_MAX;
373}
374
375ARMV7_PMSA_TEXT_SECTION
376static inline bool _ARMV7_PMSA_Is_region_enabled(uint32_t index)
377{
378 _Assert(index < _ARMV7_PMSA_Get_max_regions());
379
380 _ARMV7_Write_rgnr(ARMV7_RGNR_REGION(index));
381 _ARM_Instruction_synchronization_barrier();
382
383 return (_ARMV7_Read_drsr() & ARMV7_RSR_EN) != 0;
384}
385
386ARMV7_PMSA_TEXT_SECTION
387static inline uint32_t _ARMV7_PMSA_Find_available_region(void)
388{
389 uint32_t region_count = _ARMV7_PMSA_Get_max_regions();
390 uint32_t index;
391
392 for (index = 0; index < region_count; index++) {
393 if (!_ARMV7_PMSA_Is_region_enabled(index)) {
394 return index;
395 }
396 }
397
398 return UINT32_MAX;
399}
400
403#ifdef __cplusplus
404}
405#endif
406
407#endif /* _RTEMS_SCORE_ARMV7_PMSA_H */
This header file provides the API to read and write the AArch32 system registers.
This header file provides the interfaces of the Assert Handler.
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG and static analysis runs.
Definition: assert.h:96
The region definition is used to initialize the Memory Protection Unit (MPU).
Definition: armv7-pmsa.h:232
uint32_t size
This member defines the size in bytes of the region.
Definition: armv7-pmsa.h:241
uint32_t begin
This member defines the begin address of the region.
Definition: armv7-pmsa.h:236
uint32_t attributes
This member defines the attributes of the region.
Definition: armv7-pmsa.h:246
unsigned e
Definition: tlb.h:13