1 /*
2 * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "tgu_armv8_m_drv.h"
17
18 #include <stddef.h>
19 #include <stdbool.h>
20
21 #include "cmsis_compiler.h"
22
23 /* CTRL register bit indexes */
24 #define TGU_CTRL_DBFEN (1UL)
25 #define TGU_CTRL_DEREN (1UL << 1UL)
26 #define TGU_ARMV8_M_CFG_TGU_PRESENT (1UL << 31UL)
27
28 #define TGU_CFG_BLKSZ_MASK (15UL) /* Bits 0-3 */
29 #define TGU_CFG_NUMBLKS_MASK (15UL << 8UL) /* Bits 8-11 */
30
31 struct tgu_armv8_m_reg_map_t {
32 volatile uint32_t ctrl;
33 volatile uint32_t cfg;
34 volatile uint32_t reserved[2];
35 volatile uint32_t lutn[15];
36 };
37
38 /*
39 * Checks if the address is controlled by the TGU and returns
40 * the range index in which it is contained.
41 *
42 * \param[in] dev TGU device to initialize \ref tgu_armv8_m_dev_t
43 * \param[in] addr Address to check if it is controlled by TGU.
44 * \param[out] addr_range Range index in which it is contained.
45 *
46 * \return True if the base is controller by the range list, false otherwise.
47 */
is_ctrl_by_range_list(struct tgu_armv8_m_dev_t * dev,uint32_t addr,const struct tgu_armv8_m_mem_range_t ** addr_range)48 static uint32_t is_ctrl_by_range_list(
49 struct tgu_armv8_m_dev_t* dev,
50 uint32_t addr,
51 const struct tgu_armv8_m_mem_range_t** addr_range)
52 {
53 uint32_t i;
54 const struct tgu_armv8_m_mem_range_t* range;
55
56 for(i = 0; i < dev->data->nbr_of_ranges; i++) {
57 range = dev->data->range_list[i];
58 if(addr >= range->base && addr <= range->limit) {
59 *addr_range = range;
60 return 1;
61 }
62 }
63 return 0;
64 }
65
get_lut_masks(struct tgu_armv8_m_dev_t * dev,const uint32_t base,const uint32_t limit,const struct tgu_armv8_m_mem_range_t ** range,uint32_t * first_word_idx,uint32_t * nr_words,uint32_t * first_word_mask,uint32_t * limit_word_mask)66 static enum tgu_armv8_m_error_t get_lut_masks(
67 struct tgu_armv8_m_dev_t* dev,
68 const uint32_t base, const uint32_t limit,
69 const struct tgu_armv8_m_mem_range_t** range,
70 uint32_t *first_word_idx,
71 uint32_t *nr_words,
72 uint32_t *first_word_mask,
73 uint32_t *limit_word_mask)
74 {
75 const struct tgu_armv8_m_mem_range_t* base_range;
76 uint32_t block_size;
77 uint32_t base_block_idx;
78 uint32_t base_word_idx;
79 uint32_t blk_max;
80 const struct tgu_armv8_m_mem_range_t* limit_range;
81 uint32_t limit_block_idx;
82 uint32_t limit_word_idx;
83 uint32_t mask;
84 uint32_t norm_base;
85 uint32_t norm_limit;
86 struct tgu_armv8_m_reg_map_t* p_tgu =
87 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
88
89 /*
90 * Check that the addresses are within the controlled regions
91 * of this TGU
92 */
93 if(!is_ctrl_by_range_list(dev, base, &base_range) ||
94 !is_ctrl_by_range_list(dev, limit, &limit_range)) {
95 return TGU_INTERN_ERR_NOT_IN_RANGE;
96 }
97
98 /* Base and limit should be part of the same range */
99 if(base_range != limit_range) {
100 return TGU_INTERN_ERR_NOT_IN_RANGE;
101 }
102 *range = base_range;
103
104 block_size = ( 1 << ((p_tgu->cfg & TGU_CFG_BLKSZ_MASK) + 5));
105
106 /* Base and limit+1 addresses must be aligned on the TGU block size */
107 if(base % block_size || (limit+1) % block_size) {
108 return TGU_INTERN_ERR_NOT_ALIGNED;
109 }
110
111 /*
112 * Get a normalized address that is an offset from the beginning
113 * of the lowest range controlled by the TGU
114 */
115 norm_base = (base - base_range->base) + base_range->range_offset;
116 norm_limit = (limit - base_range->base) + base_range->range_offset;
117
118 /*
119 * Calculate block index and to which 32 bits word it belongs
120 */
121 limit_block_idx = norm_limit/block_size;
122 limit_word_idx = limit_block_idx/32;
123
124 base_block_idx = norm_base/block_size;
125 base_word_idx = base_block_idx/32;
126
127 if(base_block_idx > limit_block_idx) {
128 return TGU_INTERN_ERR_INVALID_RANGE;
129 }
130
131 /* Transmit the information to the caller */
132 *nr_words = limit_word_idx - base_word_idx + 1;
133 *first_word_idx = base_word_idx;
134
135 /* Limit to the highest block that can be configured */
136 blk_max = 15;
137
138 if((limit_word_idx > blk_max) || (base_word_idx > blk_max)) {
139 return TGU_INTERN_ERR_BLK_IDX_TOO_HIGH;
140 }
141
142 /*
143 * Create the mask for the first word to only select the limit N bits
144 */
145 *first_word_mask = ~((1 << (base_block_idx % 32)) - 1);
146
147 /*
148 * Create the mask for the limit word to select only the first M bits.
149 */
150 *limit_word_mask = (1 << ((limit_block_idx+1) % 32)) - 1;
151 /*
152 * If limit_word_mask is 0, it means that the limit touched block index is
153 * the limit in its word, so the limit word mask has all its bits selected
154 */
155 if(*limit_word_mask == 0) {
156 *limit_word_mask = 0xFFFFFFFF;
157 }
158
159 /*
160 * If the blocks to configure are all packed in one word, only
161 * touch this word.
162 * Code using the computed masks should test if this mask
163 * is non-zero, and if so, only use this one instead of the limit_word_mask
164 * and first_word_mask.
165 * As the only bits that are the same in both masks are the 1 that we want
166 * to select, just use XOR to extract them.
167 */
168 if(base_word_idx == limit_word_idx) {
169 mask = ~(*first_word_mask ^ *limit_word_mask);
170 *first_word_mask = mask;
171 *limit_word_mask = mask;
172 }
173
174 return TGU_ERR_NONE;
175 }
176
tgu_armv8_m_init(struct tgu_armv8_m_dev_t * dev,const struct tgu_armv8_m_mem_range_t ** range_list,uint8_t nbr_of_ranges)177 enum tgu_armv8_m_error_t tgu_armv8_m_init(struct tgu_armv8_m_dev_t* dev,
178 const struct tgu_armv8_m_mem_range_t** range_list,
179 uint8_t nbr_of_ranges)
180 {
181 if((range_list == NULL) || (nbr_of_ranges == 0)) {
182 return TGU_INVALID_ARG;
183 }
184
185 dev->data->range_list = range_list;
186 dev->data->nbr_of_ranges = nbr_of_ranges;
187 dev->data->is_initialized = true;
188
189 return TGU_ERR_NONE;
190 }
191
tgu_armv8_m_get_block_size(struct tgu_armv8_m_dev_t * dev,uint32_t * blk_size)192 enum tgu_armv8_m_error_t tgu_armv8_m_get_block_size(struct tgu_armv8_m_dev_t* dev,
193 uint32_t* blk_size)
194 {
195 struct tgu_armv8_m_reg_map_t* p_tgu =
196 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
197
198 if(dev->data->is_initialized != true) {
199 return TGU_NOT_INIT;
200 }
201 /* Returns block size in bytes */
202 *blk_size = ( 1 << ((p_tgu->cfg & TGU_CFG_BLKSZ_MASK) + 5));
203
204 return TGU_ERR_NONE;
205 }
206
tgu_armv8_m_get_number_of_prog_blocks(struct tgu_armv8_m_dev_t * dev,uint32_t * num_blks)207 enum tgu_armv8_m_error_t tgu_armv8_m_get_number_of_prog_blocks(struct tgu_armv8_m_dev_t* dev,
208 uint32_t* num_blks)
209 {
210 struct tgu_armv8_m_reg_map_t* p_tgu =
211 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
212
213 if(dev->data->is_initialized != true) {
214 return TGU_NOT_INIT;
215 }
216
217 *num_blks = (1 << ((p_tgu->cfg & TGU_CFG_NUMBLKS_MASK) >> 8));
218
219 return TGU_ERR_NONE;
220 }
221
tgu_armv8_m_config_region(struct tgu_armv8_m_dev_t * dev,const uint32_t base,const uint32_t limit,enum tgu_armv8_m_sec_attr_t attr)222 enum tgu_armv8_m_error_t tgu_armv8_m_config_region(struct tgu_armv8_m_dev_t* dev,
223 const uint32_t base,
224 const uint32_t limit,
225 enum tgu_armv8_m_sec_attr_t attr)
226 {
227 enum tgu_armv8_m_error_t error;
228 uint32_t first_word_idx;
229 uint32_t first_word_mask;
230 uint32_t i;
231 uint32_t limit_word_mask;
232 uint32_t limit_word_idx;
233 uint32_t nr_words;
234 const struct tgu_armv8_m_mem_range_t* range;
235 uint32_t word_value;
236 struct tgu_armv8_m_reg_map_t* p_tgu =
237 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
238
239 if(dev->data->is_initialized != true) {
240 return TGU_NOT_INIT;
241 }
242
243 /* Get the bitmasks used to select the bits in the LUT */
244 error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
245 &first_word_mask, &limit_word_mask);
246
247 limit_word_idx = first_word_idx + nr_words - 1;
248
249 if(error != TGU_ERR_NONE) {
250 /* Map internal error code lower than 0 to a generic errpr */
251 if(error < 0) {
252 return TGU_INTERN_ERR_INVALID_RANGE;
253 }
254 return (enum tgu_armv8_m_error_t)error;
255 }
256
257 /*
258 * The memory range should allow accesses in with the wanted security
259 * attribute if it requires special attribute for successful accesses
260 */
261 if(range->attr != attr) {
262 return TGU_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE;
263 }
264
265 /*
266 * Starts changing actual configuration so issue DMB to ensure every
267 * transaction has completed by now
268 */
269 __DMB();
270
271 /* If only one word needs to be touched in the LUT */
272 if(nr_words == 1) {
273 word_value = p_tgu->lutn[first_word_idx];
274 if(attr == TGU_SEC_ATTR_NONSECURE) {
275 word_value |= first_word_mask;
276 } else {
277 word_value &= ~first_word_mask;
278 }
279
280 p_tgu->lutn[first_word_idx] = word_value;
281
282 /* Commit the configuration change */
283 __DSB();
284 __ISB();
285
286 return TGU_ERR_NONE;
287 }
288
289 /* First word */
290 word_value = p_tgu->lutn[first_word_idx];
291 if(attr == TGU_SEC_ATTR_NONSECURE) {
292 word_value |= first_word_mask;
293 } else {
294 word_value &= ~first_word_mask;
295 }
296
297 /* Partially configure the first word */
298 p_tgu->lutn[first_word_idx] = word_value;
299
300 /* Fully configure the intermediate words if there are any */
301 for(i=first_word_idx+1; i<limit_word_idx; i++) {
302 if(attr == TGU_SEC_ATTR_NONSECURE) {
303 p_tgu->lutn[i] = 0xFFFFFFFF;
304 } else {
305 p_tgu->lutn[i] = 0x00000000;
306 }
307 }
308
309 /* Partially configure the limit word */
310 word_value = p_tgu->lutn[limit_word_idx];
311 if(attr == TGU_SEC_ATTR_NONSECURE) {
312 word_value |= limit_word_mask;
313 } else {
314 word_value &= ~limit_word_mask;
315 }
316
317 p_tgu->lutn[limit_word_idx] = word_value;
318
319 /* Commit the configuration change */
320 __DSB();
321 __ISB();
322
323 return TGU_ERR_NONE;
324 }
325
tgu_armv8_m_get_region_config(struct tgu_armv8_m_dev_t * dev,uint32_t base,uint32_t limit,enum tgu_armv8_m_sec_attr_t * attr)326 enum tgu_armv8_m_error_t tgu_armv8_m_get_region_config(struct tgu_armv8_m_dev_t* dev,
327 uint32_t base,
328 uint32_t limit,
329 enum tgu_armv8_m_sec_attr_t* attr)
330 {
331 enum tgu_armv8_m_sec_attr_t attr_prev;
332 uint32_t block_size;
333 uint32_t block_size_mask;
334 enum tgu_armv8_m_error_t error;
335 uint32_t first_word_idx;
336 uint32_t first_word_mask;
337 uint32_t i;
338 uint32_t limit_word_idx;
339 uint32_t limit_word_mask;
340 uint32_t nr_words;
341 struct tgu_armv8_m_reg_map_t* p_tgu =
342 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
343 const struct tgu_armv8_m_mem_range_t* range;
344 uint32_t word_value;
345
346 if(dev->data->is_initialized != true) {
347 return TGU_NOT_INIT;
348 }
349
350 if(attr == 0) {
351 return TGU_INVALID_ARG;
352 }
353
354 /*
355 * Initialize the security attribute to mixed in case of early
356 * termination of this function. A caller that does not check the
357 * returned error will act as if it does not know anything about the
358 * region queried, which is the safest bet
359 */
360 *attr = TGU_SEC_ATTR_MIXED;
361
362 /*
363 * If the base and limit are not aligned, align them and make sure
364 * that the resulting region fully includes the original region
365 */
366 block_size = ( 1 << ((p_tgu->cfg & TGU_CFG_BLKSZ_MASK) + 5));
367
368 block_size_mask = block_size - 1;
369 base &= ~(block_size_mask);
370 limit &= ~(block_size_mask);
371 limit += block_size - 1; /* Round to the upper block address,
372 * and then remove one to get the preceding
373 * address.
374 */
375
376 /* Get the bitmasks used to select the bits in the LUT */
377 error = get_lut_masks(dev, base, limit, &range, &first_word_idx, &nr_words,
378 &first_word_mask, &limit_word_mask);
379
380 limit_word_idx = first_word_idx+nr_words - 1;
381
382 if(error != TGU_ERR_NONE) {
383 /* Map internal error code lower than 0 to generic error */
384 if(error < 0) {
385 return TGU_INTERN_ERR_INVALID_RANGE;
386 }
387 return (enum tgu_armv8_m_error_t)error;
388 }
389
390 /* If only one word needs to be touched in the LUT */
391 if(nr_words == 1) {
392 word_value = p_tgu->lutn[first_word_idx];
393 word_value &= first_word_mask;
394 if(word_value == 0) {
395 *attr = TGU_SEC_ATTR_SECURE;
396 /*
397 * If there are differences between the mask and the word value,
398 * it means that the security attributes of blocks are mixed
399 */
400 } else if(word_value ^ first_word_mask) {
401 *attr = TGU_SEC_ATTR_MIXED;
402 } else {
403 *attr = TGU_SEC_ATTR_NONSECURE;
404 }
405 return TGU_ERR_NONE;
406 }
407
408 /* Get the partial configuration of the first word */
409 word_value = p_tgu->lutn[first_word_idx] & first_word_mask;
410 if(word_value == 0x00000000) {
411 *attr = TGU_SEC_ATTR_SECURE;
412 } else if(word_value ^ first_word_mask) {
413 *attr = TGU_SEC_ATTR_MIXED;
414 /*
415 * Bail out as the security attribute will be the same regardless
416 * of the configuration of other blocks
417 */
418 return TGU_ERR_NONE;
419 } else {
420 *attr = TGU_SEC_ATTR_NONSECURE;
421 }
422 /*
423 * Store the current found attribute, to check that all the blocks indeed
424 * have the same security attribute.
425 */
426 attr_prev = *attr;
427
428 /* Get the configuration of the intermediate words if there are any */
429 for(i=first_word_idx+1; i<limit_word_idx; i++) {
430 word_value = p_tgu->lutn[i];
431 if(word_value == 0x00000000) {
432 *attr = TGU_SEC_ATTR_SECURE;
433 } else if(word_value == 0xFFFFFFFF) {
434 *attr = TGU_SEC_ATTR_NONSECURE;
435 } else {
436 *attr = TGU_SEC_ATTR_MIXED;
437 return TGU_ERR_NONE;
438 }
439
440 /* If the attribute is different than the one found before, bail out */
441 if(*attr != attr_prev) {
442 *attr = TGU_SEC_ATTR_MIXED;
443 return TGU_ERR_NONE;
444 }
445 attr_prev = *attr;
446 }
447
448 /* Get the partial configuration of the limit word */
449 word_value = p_tgu->lutn[limit_word_idx] & limit_word_mask;
450 if(word_value == 0x00000000) {
451 *attr = TGU_SEC_ATTR_SECURE;
452 } else if(word_value ^ first_word_mask) {
453 *attr = TGU_SEC_ATTR_MIXED;
454 return TGU_ERR_NONE;
455 } else {
456 *attr = TGU_SEC_ATTR_NONSECURE;
457 }
458
459 if(*attr != attr_prev) {
460 *attr = TGU_SEC_ATTR_MIXED;
461 return TGU_ERR_NONE;
462 }
463
464 return TGU_ERR_NONE;
465 }
466
tgu_armv8_m_get_ctrl(struct tgu_armv8_m_dev_t * dev,uint32_t * ctrl_val)467 enum tgu_armv8_m_error_t tgu_armv8_m_get_ctrl(struct tgu_armv8_m_dev_t* dev,
468 uint32_t* ctrl_val)
469 {
470 struct tgu_armv8_m_reg_map_t* p_tgu =
471 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
472
473 if(dev->data->is_initialized != true) {
474 return TGU_NOT_INIT;
475 }
476
477 if(ctrl_val == 0) {
478 return TGU_INVALID_ARG;
479 }
480
481 *ctrl_val = p_tgu->ctrl;
482
483 return TGU_ERR_NONE;
484 }
485
tgu_armv8_m_set_ctrl(struct tgu_armv8_m_dev_t * dev,uint32_t tgu_ctrl)486 enum tgu_armv8_m_error_t tgu_armv8_m_set_ctrl(struct tgu_armv8_m_dev_t* dev,
487 uint32_t tgu_ctrl)
488 {
489 struct tgu_armv8_m_reg_map_t* p_tgu =
490 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
491
492 if(dev->data->is_initialized != true) {
493 return TGU_NOT_INIT;
494 }
495
496 p_tgu->ctrl = tgu_ctrl;
497
498 return TGU_ERR_NONE;
499 }
500
tgu_armv8_m_is_tgu_present(struct tgu_armv8_m_dev_t * dev,bool * tgu_present)501 enum tgu_armv8_m_error_t tgu_armv8_m_is_tgu_present(struct tgu_armv8_m_dev_t* dev,
502 bool* tgu_present)
503 {
504 struct tgu_armv8_m_reg_map_t* p_tgu =
505 (struct tgu_armv8_m_reg_map_t*)dev->cfg->base;
506
507 if(dev->data->is_initialized != true) {
508 return TGU_NOT_INIT;
509 }
510
511 *tgu_present = (bool)(p_tgu->cfg & TGU_ARMV8_M_CFG_TGU_PRESENT);
512
513 return TGU_ERR_NONE;
514 }
515