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