xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/arm/cmse.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
13ad841b2Smrg /* ARMv8-M Security Extensions routines.
2*4c3eb207Smrg    Copyright (C) 2015-2020 Free Software Foundation, Inc.
33ad841b2Smrg    Contributed by ARM Ltd.
43ad841b2Smrg 
53ad841b2Smrg    This file is free software; you can redistribute it and/or modify it
63ad841b2Smrg    under the terms of the GNU General Public License as published by the
73ad841b2Smrg    Free Software Foundation; either version 3, or (at your option) any
83ad841b2Smrg    later version.
93ad841b2Smrg 
103ad841b2Smrg    This file is distributed in the hope that it will be useful, but
113ad841b2Smrg    WITHOUT ANY WARRANTY; without even the implied warranty of
123ad841b2Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
133ad841b2Smrg    General Public License for more details.
143ad841b2Smrg 
153ad841b2Smrg    Under Section 7 of GPL version 3, you are granted additional
163ad841b2Smrg    permissions described in the GCC Runtime Library Exception, version
173ad841b2Smrg    3.1, as published by the Free Software Foundation.
183ad841b2Smrg 
193ad841b2Smrg    You should have received a copy of the GNU General Public License and
203ad841b2Smrg    a copy of the GCC Runtime Library Exception along with this program;
213ad841b2Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
223ad841b2Smrg    <http://www.gnu.org/licenses/>.  */
233ad841b2Smrg 
243ad841b2Smrg 
253ad841b2Smrg #if __ARM_FEATURE_CMSE & 1
263ad841b2Smrg 
273ad841b2Smrg #include <arm_cmse.h>
283ad841b2Smrg 
293ad841b2Smrg /* ARM intrinsic function to perform a permission check on a given
303ad841b2Smrg    address range.  See ACLE changes for ARMv8-M.  */
313ad841b2Smrg 
323ad841b2Smrg void *
33*4c3eb207Smrg __attribute__ ((warn_unused_result))
cmse_check_address_range(void * p,size_t size,int flags)343ad841b2Smrg cmse_check_address_range (void *p, size_t size, int flags)
353ad841b2Smrg {
363ad841b2Smrg   cmse_address_info_t permb, perme;
373ad841b2Smrg   char *pb = (char *) p, *pe;
383ad841b2Smrg 
393ad841b2Smrg   /* Check if the range wraps around.  */
40627f7eb2Smrg   if (__UINTPTR_MAX__ - (__UINTPTR_TYPE__) p < size)
413ad841b2Smrg     return NULL;
423ad841b2Smrg 
433ad841b2Smrg   /* Check if an unknown flag is present.  */
443ad841b2Smrg   int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
453ad841b2Smrg   int known_secure_level = CMSE_MPU_UNPRIV;
463ad841b2Smrg #if __ARM_FEATURE_CMSE & 2
473ad841b2Smrg   known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
483ad841b2Smrg   known_secure_level |= CMSE_MPU_NONSECURE;
493ad841b2Smrg #endif
503ad841b2Smrg   if (flags & (~known))
513ad841b2Smrg     return NULL;
523ad841b2Smrg 
533ad841b2Smrg   /* Execute the right variant of the TT instructions.  */
543ad841b2Smrg   pe = pb + size - 1;
55627f7eb2Smrg   const int singleCheck
56627f7eb2Smrg     = (((__UINTPTR_TYPE__) pb ^ (__UINTPTR_TYPE__) pe) < 32);
573ad841b2Smrg   switch (flags & known_secure_level)
583ad841b2Smrg     {
593ad841b2Smrg     case 0:
603ad841b2Smrg       permb = cmse_TT (pb);
613ad841b2Smrg       perme = singleCheck ? permb : cmse_TT (pe);
623ad841b2Smrg       break;
633ad841b2Smrg     case CMSE_MPU_UNPRIV:
643ad841b2Smrg       permb = cmse_TTT (pb);
653ad841b2Smrg       perme = singleCheck ? permb : cmse_TTT (pe);
663ad841b2Smrg       break;
673ad841b2Smrg #if __ARM_FEATURE_CMSE & 2
683ad841b2Smrg     case CMSE_MPU_NONSECURE:
693ad841b2Smrg       permb = cmse_TTA (pb);
703ad841b2Smrg       perme = singleCheck ? permb : cmse_TTA (pe);
713ad841b2Smrg       break;
723ad841b2Smrg     case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
733ad841b2Smrg       permb = cmse_TTAT (pb);
743ad841b2Smrg       perme = singleCheck ? permb : cmse_TTAT (pe);
753ad841b2Smrg       break;
763ad841b2Smrg #endif
773ad841b2Smrg     default:
783ad841b2Smrg       /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
793ad841b2Smrg 	 __ARM_FEATURE_CMSE & 2 == 0.  */
803ad841b2Smrg       return NULL;
813ad841b2Smrg     }
823ad841b2Smrg 
833ad841b2Smrg   /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
843ad841b2Smrg   if (permb.value != perme.value)
853ad841b2Smrg     return NULL;
863ad841b2Smrg 
873ad841b2Smrg   /* Check the permissions on the range.  */
883ad841b2Smrg   switch (flags & (~known_secure_level))
893ad841b2Smrg     {
903ad841b2Smrg #if __ARM_FEATURE_CMSE & 2
913ad841b2Smrg     case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
923ad841b2Smrg     case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
933ad841b2Smrg       return permb.flags.nonsecure_readwrite_ok	? p : NULL;
943ad841b2Smrg     case CMSE_MPU_READ | CMSE_AU_NONSECURE:
953ad841b2Smrg       return permb.flags.nonsecure_read_ok	? p : NULL;
963ad841b2Smrg     case CMSE_AU_NONSECURE:
973ad841b2Smrg       return permb.flags.secure			? NULL : p;
983ad841b2Smrg #endif
993ad841b2Smrg     case CMSE_MPU_READ | CMSE_MPU_READWRITE:
1003ad841b2Smrg     case		 CMSE_MPU_READWRITE:
1013ad841b2Smrg       return permb.flags.readwrite_ok		? p : NULL;
1023ad841b2Smrg     case CMSE_MPU_READ:
1033ad841b2Smrg       return permb.flags.read_ok		? p : NULL;
1043ad841b2Smrg     default:
1053ad841b2Smrg       return NULL;
1063ad841b2Smrg     }
1073ad841b2Smrg }
1083ad841b2Smrg 
1093ad841b2Smrg 
1103ad841b2Smrg #endif /* __ARM_FEATURE_CMSE & 1.  */
111