brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · ecf50ec Raw
218 lines · c
1//===---- arm_cmse.h - Arm CMSE support -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef __ARM_CMSE_H10#define __ARM_CMSE_H11 12#if (__ARM_FEATURE_CMSE & 0x1)13#include <stddef.h>14#include <stdint.h>15 16#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2)17#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */18#define CMSE_AU_NONSECURE  2 /* checks if permissions have secure field unset */19#define CMSE_MPU_UNPRIV    4 /* sets T flag on TT insrtuction */20#define CMSE_MPU_READ      8 /* checks if read_ok field is set */21#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */22#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE)23 24#define cmse_check_pointed_object(p, f) \25  cmse_check_address_range((p), sizeof(*(p)), (f))26 27#if defined(__cplusplus)28extern "C" {29#endif30 31typedef union {32  struct cmse_address_info {33#ifdef __ARM_BIG_ENDIAN34    /* __ARM_BIG_ENDIAN */35#if (__ARM_CMSE_SECURE_MODE)36    unsigned idau_region : 8;37    unsigned idau_region_valid : 1;38    unsigned secure : 1;39    unsigned nonsecure_readwrite_ok : 1;40    unsigned nonsecure_read_ok : 1;41#else42    unsigned : 12;43#endif44    unsigned readwrite_ok : 1;45    unsigned read_ok : 1;46#if (__ARM_CMSE_SECURE_MODE)47    unsigned sau_region_valid : 1;48#else49    unsigned : 1;50#endif51    unsigned mpu_region_valid : 1;52#if (__ARM_CMSE_SECURE_MODE)53    unsigned sau_region : 8;54#else55    unsigned : 8;56#endif57    unsigned mpu_region : 8;58 59#else /* __ARM_LITTLE_ENDIAN */60    unsigned mpu_region : 8;61#if (__ARM_CMSE_SECURE_MODE)62    unsigned sau_region : 8;63#else64    unsigned : 8;65#endif66    unsigned mpu_region_valid : 1;67#if (__ARM_CMSE_SECURE_MODE)68    unsigned sau_region_valid : 1;69#else70    unsigned : 1;71#endif72    unsigned read_ok : 1;73    unsigned readwrite_ok : 1;74#if (__ARM_CMSE_SECURE_MODE)75    unsigned nonsecure_read_ok : 1;76    unsigned nonsecure_readwrite_ok : 1;77    unsigned secure : 1;78    unsigned idau_region_valid : 1;79    unsigned idau_region : 8;80#else81    unsigned : 12;82#endif83#endif /*__ARM_LITTLE_ENDIAN */84  } flags;85  unsigned value;86} cmse_address_info_t;87 88static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))89cmse_TT(void *__p) {90  cmse_address_info_t __u;91  __u.value = __builtin_arm_cmse_TT(__p);92  return __u;93}94static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))95cmse_TTT(void *__p) {96  cmse_address_info_t __u;97  __u.value = __builtin_arm_cmse_TTT(__p);98  return __u;99}100 101#if __ARM_CMSE_SECURE_MODE102static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))103cmse_TTA(void *__p) {104  cmse_address_info_t __u;105  __u.value = __builtin_arm_cmse_TTA(__p);106  return __u;107}108static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))109cmse_TTAT(void *__p) {110  cmse_address_info_t __u;111  __u.value = __builtin_arm_cmse_TTAT(__p);112  return __u;113}114#endif115 116#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p)))117#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p)))118 119#if __ARM_CMSE_SECURE_MODE120#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p)))121#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p)))122#endif123 124static void *__attribute__((__always_inline__))125cmse_check_address_range(void *__pb, size_t __s, int __flags) {126  uintptr_t __begin = (uintptr_t)__pb;127  uintptr_t __end = __begin + __s - 1;128 129  if (__end < __begin)130    return NULL; /* wrap around check */131 132  /* Check whether the range crosses a 32-bytes aligned address */133  const int __single_check = (__begin ^ __end) < 0x20u;134 135  /* execute the right variant of the TT instructions */136  void *__pe = (void *)__end;137  cmse_address_info_t __permb, __perme;138  switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {139  case 0:140    __permb = cmse_TT(__pb);141    __perme = __single_check ? __permb : cmse_TT(__pe);142    break;143  case CMSE_MPU_UNPRIV:144    __permb = cmse_TTT(__pb);145    __perme = __single_check ? __permb : cmse_TTT(__pe);146    break;147#if __ARM_CMSE_SECURE_MODE148  case CMSE_MPU_NONSECURE:149    __permb = cmse_TTA(__pb);150    __perme = __single_check ? __permb : cmse_TTA(__pe);151    break;152  case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:153    __permb = cmse_TTAT(__pb);154    __perme = __single_check ? __permb : cmse_TTAT(__pe);155    break;156#endif157  /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */158  default:159    return NULL;160  }161 162  /* check that the range does not cross MPU, SAU, or IDAU region boundaries */163  if (__permb.value != __perme.value)164    return NULL;165#if !(__ARM_CMSE_SECURE_MODE)166  /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */167  if (__flags & CMSE_AU_NONSECURE)168    return NULL;169#endif170 171  /* check the permission on the range */172  switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {173#if (__ARM_CMSE_SECURE_MODE)174  case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:175  case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:176    return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL;177 178  case CMSE_MPU_READ | CMSE_AU_NONSECURE:179    return __permb.flags.nonsecure_read_ok ? __pb : NULL;180 181  case CMSE_AU_NONSECURE:182    return __permb.flags.secure ? NULL : __pb;183#endif184  case CMSE_MPU_READ | CMSE_MPU_READWRITE:185  case CMSE_MPU_READWRITE:186    return __permb.flags.readwrite_ok ? __pb : NULL;187 188  case CMSE_MPU_READ:189    return __permb.flags.read_ok ? __pb : NULL;190 191  default:192    return NULL;193  }194}195 196#if __ARM_CMSE_SECURE_MODE197static int __attribute__((__always_inline__, __nodebug__))198cmse_nonsecure_caller(void) {199  return !((uintptr_t)__builtin_return_address(0) & 1);200}201 202#define cmse_nsfptr_create(p)                                                  \203  __builtin_bit_cast(__typeof__(p),                                            \204                     (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1))205 206#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0)207 208#endif /* __ARM_CMSE_SECURE_MODE */209 210void __attribute__((__noreturn__)) cmse_abort(void);211#if defined(__cplusplus)212}213#endif214 215#endif /* (__ARM_FEATURE_CMSE & 0x1) */216 217#endif /* __ARM_CMSE_H */218