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