xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/arm/cmse.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1b17d1066Smrg /* ARMv8-M Security Extensions routines.
2*b1e83836Smrg    Copyright (C) 2015-2022 Free Software Foundation, Inc.
3b17d1066Smrg    Contributed by ARM Ltd.
4b17d1066Smrg 
5b17d1066Smrg    This file is free software; you can redistribute it and/or modify it
6b17d1066Smrg    under the terms of the GNU General Public License as published by the
7b17d1066Smrg    Free Software Foundation; either version 3, or (at your option) any
8b17d1066Smrg    later version.
9b17d1066Smrg 
10b17d1066Smrg    This file is distributed in the hope that it will be useful, but
11b17d1066Smrg    WITHOUT ANY WARRANTY; without even the implied warranty of
12b17d1066Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13b17d1066Smrg    General Public License for more details.
14b17d1066Smrg 
15b17d1066Smrg    Under Section 7 of GPL version 3, you are granted additional
16b17d1066Smrg    permissions described in the GCC Runtime Library Exception, version
17b17d1066Smrg    3.1, as published by the Free Software Foundation.
18b17d1066Smrg 
19b17d1066Smrg    You should have received a copy of the GNU General Public License and
20b17d1066Smrg    a copy of the GCC Runtime Library Exception along with this program;
21b17d1066Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22b17d1066Smrg    <http://www.gnu.org/licenses/>.  */
23b17d1066Smrg 
24b17d1066Smrg 
25b17d1066Smrg #if __ARM_FEATURE_CMSE & 1
26b17d1066Smrg 
27b17d1066Smrg #include <arm_cmse.h>
28b17d1066Smrg 
29b17d1066Smrg /* ARM intrinsic function to perform a permission check on a given
30b17d1066Smrg    address range.  See ACLE changes for ARMv8-M.  */
31b17d1066Smrg 
32b17d1066Smrg void *
33fb8a8121Smrg __attribute__ ((warn_unused_result))
cmse_check_address_range(void * p,size_t size,int flags)34b17d1066Smrg cmse_check_address_range (void *p, size_t size, int flags)
35b17d1066Smrg {
36b17d1066Smrg   cmse_address_info_t permb, perme;
37b17d1066Smrg   char *pb = (char *) p, *pe;
38b17d1066Smrg 
39b17d1066Smrg   /* Check if the range wraps around.  */
40181254a7Smrg   if (__UINTPTR_MAX__ - (__UINTPTR_TYPE__) p < size)
41b17d1066Smrg     return NULL;
42b17d1066Smrg 
43b17d1066Smrg   /* Check if an unknown flag is present.  */
44b17d1066Smrg   int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
45b17d1066Smrg   int known_secure_level = CMSE_MPU_UNPRIV;
46b17d1066Smrg #if __ARM_FEATURE_CMSE & 2
47b17d1066Smrg   known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
48b17d1066Smrg   known_secure_level |= CMSE_MPU_NONSECURE;
49b17d1066Smrg #endif
50b17d1066Smrg   if (flags & (~known))
51b17d1066Smrg     return NULL;
52b17d1066Smrg 
53b17d1066Smrg   /* Execute the right variant of the TT instructions.  */
54b17d1066Smrg   pe = pb + size - 1;
55181254a7Smrg   const int singleCheck
56181254a7Smrg     = (((__UINTPTR_TYPE__) pb ^ (__UINTPTR_TYPE__) pe) < 32);
57b17d1066Smrg   switch (flags & known_secure_level)
58b17d1066Smrg     {
59b17d1066Smrg     case 0:
60b17d1066Smrg       permb = cmse_TT (pb);
61b17d1066Smrg       perme = singleCheck ? permb : cmse_TT (pe);
62b17d1066Smrg       break;
63b17d1066Smrg     case CMSE_MPU_UNPRIV:
64b17d1066Smrg       permb = cmse_TTT (pb);
65b17d1066Smrg       perme = singleCheck ? permb : cmse_TTT (pe);
66b17d1066Smrg       break;
67b17d1066Smrg #if __ARM_FEATURE_CMSE & 2
68b17d1066Smrg     case CMSE_MPU_NONSECURE:
69b17d1066Smrg       permb = cmse_TTA (pb);
70b17d1066Smrg       perme = singleCheck ? permb : cmse_TTA (pe);
71b17d1066Smrg       break;
72b17d1066Smrg     case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
73b17d1066Smrg       permb = cmse_TTAT (pb);
74b17d1066Smrg       perme = singleCheck ? permb : cmse_TTAT (pe);
75b17d1066Smrg       break;
76b17d1066Smrg #endif
77b17d1066Smrg     default:
78b17d1066Smrg       /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
79b17d1066Smrg 	 __ARM_FEATURE_CMSE & 2 == 0.  */
80b17d1066Smrg       return NULL;
81b17d1066Smrg     }
82b17d1066Smrg 
83b17d1066Smrg   /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
84b17d1066Smrg   if (permb.value != perme.value)
85b17d1066Smrg     return NULL;
86b17d1066Smrg 
87b17d1066Smrg   /* Check the permissions on the range.  */
88b17d1066Smrg   switch (flags & (~known_secure_level))
89b17d1066Smrg     {
90b17d1066Smrg #if __ARM_FEATURE_CMSE & 2
91b17d1066Smrg     case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
92b17d1066Smrg     case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
93b17d1066Smrg       return permb.flags.nonsecure_readwrite_ok	? p : NULL;
94b17d1066Smrg     case CMSE_MPU_READ | CMSE_AU_NONSECURE:
95b17d1066Smrg       return permb.flags.nonsecure_read_ok	? p : NULL;
96b17d1066Smrg     case CMSE_AU_NONSECURE:
97b17d1066Smrg       return permb.flags.secure			? NULL : p;
98b17d1066Smrg #endif
99b17d1066Smrg     case CMSE_MPU_READ | CMSE_MPU_READWRITE:
100b17d1066Smrg     case		 CMSE_MPU_READWRITE:
101b17d1066Smrg       return permb.flags.readwrite_ok		? p : NULL;
102b17d1066Smrg     case CMSE_MPU_READ:
103b17d1066Smrg       return permb.flags.read_ok		? p : NULL;
104b17d1066Smrg     default:
105b17d1066Smrg       return NULL;
106b17d1066Smrg     }
107b17d1066Smrg }
108b17d1066Smrg 
109b17d1066Smrg 
110b17d1066Smrg #endif /* __ARM_FEATURE_CMSE & 1.  */
111