1356843Sdim//===---- arm_cmse.h - Arm CMSE support -----------------------------------===// 2356843Sdim// 3356843Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4356843Sdim// See https://llvm.org/LICENSE.txt for license information. 5356843Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6356843Sdim// 7356843Sdim//===----------------------------------------------------------------------===// 8356843Sdim 9356843Sdim#ifndef __ARM_CMSE_H 10356843Sdim#define __ARM_CMSE_H 11356843Sdim 12356843Sdim#if (__ARM_FEATURE_CMSE & 0x1) 13356843Sdim#include <stddef.h> 14356843Sdim#include <stdint.h> 15356843Sdim 16356843Sdim#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2) 17356843Sdim#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */ 18356843Sdim#define CMSE_AU_NONSECURE 2 /* checks if permissions have secure field unset */ 19356843Sdim#define CMSE_MPU_UNPRIV 4 /* sets T flag on TT insrtuction */ 20356843Sdim#define CMSE_MPU_READ 8 /* checks if read_ok field is set */ 21356843Sdim#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */ 22356843Sdim#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE) 23356843Sdim 24356843Sdim#define cmse_check_pointed_object(p, f) \ 25356843Sdim cmse_check_address_range((p), sizeof(*(p)), (f)) 26356843Sdim 27356843Sdim#if defined(__cplusplus) 28356843Sdimextern "C" { 29356843Sdim#endif 30356843Sdim 31356843Sdimtypedef union { 32356843Sdim struct cmse_address_info { 33356843Sdim#ifdef __ARM_BIG_ENDIAN 34356843Sdim /* __ARM_BIG_ENDIAN */ 35356843Sdim#if (__ARM_CMSE_SECURE_MODE) 36356843Sdim unsigned idau_region : 8; 37356843Sdim unsigned idau_region_valid : 1; 38356843Sdim unsigned secure : 1; 39356843Sdim unsigned nonsecure_readwrite_ok : 1; 40356843Sdim unsigned nonsecure_read_ok : 1; 41356843Sdim#else 42356843Sdim unsigned : 12; 43356843Sdim#endif 44356843Sdim unsigned readwrite_ok : 1; 45356843Sdim unsigned read_ok : 1; 46356843Sdim#if (__ARM_CMSE_SECURE_MODE) 47356843Sdim unsigned sau_region_valid : 1; 48356843Sdim#else 49356843Sdim unsigned : 1; 50356843Sdim#endif 51356843Sdim unsigned mpu_region_valid : 1; 52356843Sdim#if (__ARM_CMSE_SECURE_MODE) 53356843Sdim unsigned sau_region : 8; 54356843Sdim#else 55356843Sdim unsigned : 8; 56356843Sdim#endif 57356843Sdim unsigned mpu_region : 8; 58356843Sdim 59356843Sdim#else /* __ARM_LITTLE_ENDIAN */ 60356843Sdim unsigned mpu_region : 8; 61356843Sdim#if (__ARM_CMSE_SECURE_MODE) 62356843Sdim unsigned sau_region : 8; 63356843Sdim#else 64356843Sdim unsigned : 8; 65356843Sdim#endif 66356843Sdim unsigned mpu_region_valid : 1; 67356843Sdim#if (__ARM_CMSE_SECURE_MODE) 68356843Sdim unsigned sau_region_valid : 1; 69356843Sdim#else 70356843Sdim unsigned : 1; 71356843Sdim#endif 72356843Sdim unsigned read_ok : 1; 73356843Sdim unsigned readwrite_ok : 1; 74356843Sdim#if (__ARM_CMSE_SECURE_MODE) 75356843Sdim unsigned nonsecure_read_ok : 1; 76356843Sdim unsigned nonsecure_readwrite_ok : 1; 77356843Sdim unsigned secure : 1; 78356843Sdim unsigned idau_region_valid : 1; 79356843Sdim unsigned idau_region : 8; 80356843Sdim#else 81356843Sdim unsigned : 12; 82356843Sdim#endif 83356843Sdim#endif /*__ARM_LITTLE_ENDIAN */ 84356843Sdim } flags; 85356843Sdim unsigned value; 86356843Sdim} cmse_address_info_t; 87356843Sdim 88356843Sdimstatic cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 89356843Sdimcmse_TT(void *__p) { 90356843Sdim cmse_address_info_t __u; 91356843Sdim __u.value = __builtin_arm_cmse_TT(__p); 92356843Sdim return __u; 93356843Sdim} 94356843Sdimstatic cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 95356843Sdimcmse_TTT(void *__p) { 96356843Sdim cmse_address_info_t __u; 97356843Sdim __u.value = __builtin_arm_cmse_TTT(__p); 98356843Sdim return __u; 99356843Sdim} 100356843Sdim 101356843Sdim#if __ARM_CMSE_SECURE_MODE 102356843Sdimstatic cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 103356843Sdimcmse_TTA(void *__p) { 104356843Sdim cmse_address_info_t __u; 105356843Sdim __u.value = __builtin_arm_cmse_TTA(__p); 106356843Sdim return __u; 107356843Sdim} 108356843Sdimstatic cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) 109356843Sdimcmse_TTAT(void *__p) { 110356843Sdim cmse_address_info_t __u; 111356843Sdim __u.value = __builtin_arm_cmse_TTAT(__p); 112356843Sdim return __u; 113356843Sdim} 114356843Sdim#endif 115356843Sdim 116356843Sdim#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p))) 117356843Sdim#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p))) 118356843Sdim 119356843Sdim#if __ARM_CMSE_SECURE_MODE 120356843Sdim#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p))) 121356843Sdim#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p))) 122356843Sdim#endif 123356843Sdim 124356843Sdimstatic void *__attribute__((__always_inline__)) 125356843Sdimcmse_check_address_range(void *__pb, size_t __s, int __flags) { 126356843Sdim uintptr_t __begin = (uintptr_t)__pb; 127356843Sdim uintptr_t __end = __begin + __s - 1; 128356843Sdim 129356843Sdim if (__end < __begin) 130356843Sdim return NULL; /* wrap around check */ 131356843Sdim 132356843Sdim /* Check whether the range crosses a 32-bytes aligned address */ 133356843Sdim const int __single_check = (__begin ^ __end) < 0x20u; 134356843Sdim 135356843Sdim /* execute the right variant of the TT instructions */ 136356843Sdim void *__pe = (void *)__end; 137356843Sdim cmse_address_info_t __permb, __perme; 138356843Sdim switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { 139356843Sdim case 0: 140356843Sdim __permb = cmse_TT(__pb); 141356843Sdim __perme = __single_check ? __permb : cmse_TT(__pe); 142356843Sdim break; 143356843Sdim case CMSE_MPU_UNPRIV: 144356843Sdim __permb = cmse_TTT(__pb); 145356843Sdim __perme = __single_check ? __permb : cmse_TTT(__pe); 146356843Sdim break; 147356843Sdim#if __ARM_CMSE_SECURE_MODE 148356843Sdim case CMSE_MPU_NONSECURE: 149356843Sdim __permb = cmse_TTA(__pb); 150356843Sdim __perme = __single_check ? __permb : cmse_TTA(__pe); 151356843Sdim break; 152356843Sdim case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE: 153356843Sdim __permb = cmse_TTAT(__pb); 154356843Sdim __perme = __single_check ? __permb : cmse_TTAT(__pe); 155356843Sdim break; 156356843Sdim#endif 157356843Sdim /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */ 158356843Sdim default: 159356843Sdim return NULL; 160356843Sdim } 161356843Sdim 162356843Sdim /* check that the range does not cross MPU, SAU, or IDAU region boundaries */ 163356843Sdim if (__permb.value != __perme.value) 164356843Sdim return NULL; 165356843Sdim#if !(__ARM_CMSE_SECURE_MODE) 166356843Sdim /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */ 167356843Sdim if (__flags & CMSE_AU_NONSECURE) 168356843Sdim return NULL; 169356843Sdim#endif 170356843Sdim 171356843Sdim /* check the permission on the range */ 172356843Sdim switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { 173356843Sdim#if (__ARM_CMSE_SECURE_MODE) 174356843Sdim case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: 175356843Sdim case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: 176356843Sdim return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL; 177356843Sdim 178356843Sdim case CMSE_MPU_READ | CMSE_AU_NONSECURE: 179356843Sdim return __permb.flags.nonsecure_read_ok ? __pb : NULL; 180356843Sdim 181356843Sdim case CMSE_AU_NONSECURE: 182356843Sdim return __permb.flags.secure ? NULL : __pb; 183356843Sdim#endif 184356843Sdim case CMSE_MPU_READ | CMSE_MPU_READWRITE: 185356843Sdim case CMSE_MPU_READWRITE: 186356843Sdim return __permb.flags.readwrite_ok ? __pb : NULL; 187356843Sdim 188356843Sdim case CMSE_MPU_READ: 189356843Sdim return __permb.flags.read_ok ? __pb : NULL; 190356843Sdim 191356843Sdim default: 192356843Sdim return NULL; 193356843Sdim } 194356843Sdim} 195356843Sdim 196356843Sdim#if __ARM_CMSE_SECURE_MODE 197356843Sdimstatic int __attribute__((__always_inline__, __nodebug__)) 198356843Sdimcmse_nonsecure_caller(void) { 199356843Sdim return !((uintptr_t)__builtin_return_address(0) & 1); 200356843Sdim} 201356843Sdim 202356843Sdim#define cmse_nsfptr_create(p) \ 203356843Sdim __builtin_bit_cast(__typeof__(p), \ 204356843Sdim (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1)) 205356843Sdim 206356843Sdim#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0) 207356843Sdim 208356843Sdim#endif /* __ARM_CMSE_SECURE_MODE */ 209356843Sdim 210356843Sdimvoid __attribute__((__noreturn__)) cmse_abort(void); 211356843Sdim#if defined(__cplusplus) 212356843Sdim} 213356843Sdim#endif 214356843Sdim 215356843Sdim#endif /* (__ARM_FEATURE_CMSE & 0x1) */ 216356843Sdim 217356843Sdim#endif /* __ARM_CMSE_H */ 218