[clang] 600d123 - [ARM][CMSE] Add CMSE header and builtins

Momchil Velikov via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 12 07:01:24 PST 2019


Author: Momchil Velikov
Date: 2019-12-12T15:01:14Z
New Revision: 600d123c6ff16180a20ebb9b55476257bf69513a

URL: https://github.com/llvm/llvm-project/commit/600d123c6ff16180a20ebb9b55476257bf69513a
DIFF: https://github.com/llvm/llvm-project/commit/600d123c6ff16180a20ebb9b55476257bf69513a.diff

LOG: [ARM][CMSE] Add CMSE header and builtins

This is patch C2 as mentioned in RFC
http://lists.llvm.org/pipermail/cfe-dev/2019-March/061834.html

This adds CMSE builtin functions, and introduces arm_cmse.h header which has
useful macros, functions, and data types for end-users of CMSE.

Patch by Javed Absar.

Diferential Revision: https://reviews.llvm.org/D70817

Added: 
    clang/lib/Headers/arm_cmse.h
    clang/test/CodeGen/arm-cmse-nonsecure.c
    clang/test/CodeGen/arm-cmse-secure.c
    clang/test/CodeGen/arm-cmse.c
    clang/test/Headers/arm-cmse-header-ns.c
    clang/test/Headers/arm-cmse-header.c

Modified: 
    clang/include/clang/Basic/BuiltinsARM.def
    clang/lib/Headers/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/BuiltinsARM.def b/clang/include/clang/Basic/BuiltinsARM.def
index 81991a57e2bd..848abb44ad36 100644
--- a/clang/include/clang/Basic/BuiltinsARM.def
+++ b/clang/include/clang/Basic/BuiltinsARM.def
@@ -166,6 +166,12 @@ BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc")
 BUILTIN(__builtin_arm_crc32d, "UiUiLLUi", "nc")
 BUILTIN(__builtin_arm_crc32cd, "UiUiLLUi", "nc")
 
+// ARMv8-M Security Extensions a.k.a CMSE
+BUILTIN(__builtin_arm_cmse_TT, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTT, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTA, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTAT, "Uiv*", "n")
+
 // HINT
 BUILTIN(__builtin_arm_nop, "v", "")
 BUILTIN(__builtin_arm_yield, "v", "")

diff  --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index 8ff648fdb4e0..85c3124234ad 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -3,6 +3,7 @@ set(files
   altivec.h
   ammintrin.h
   arm_acle.h
+  arm_cmse.h
   armintr.h
   arm64intr.h
   avx2intrin.h

diff  --git a/clang/lib/Headers/arm_cmse.h b/clang/lib/Headers/arm_cmse.h
new file mode 100644
index 000000000000..ecf50ecc5c8e
--- /dev/null
+++ b/clang/lib/Headers/arm_cmse.h
@@ -0,0 +1,217 @@
+//===---- arm_cmse.h - Arm CMSE support -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ARM_CMSE_H
+#define __ARM_CMSE_H
+
+#if (__ARM_FEATURE_CMSE & 0x1)
+#include <stddef.h>
+#include <stdint.h>
+
+#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2)
+#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */
+#define CMSE_AU_NONSECURE  2 /* checks if permissions have secure field unset */
+#define CMSE_MPU_UNPRIV    4 /* sets T flag on TT insrtuction */
+#define CMSE_MPU_READ      8 /* checks if read_ok field is set */
+#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */
+#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE)
+
+#define cmse_check_pointed_object(p, f) \
+  cmse_check_address_range((p), sizeof(*(p)), (f))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef union {
+  struct cmse_address_info {
+#ifdef __ARM_BIG_ENDIAN
+    /* __ARM_BIG_ENDIAN */
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned idau_region : 8;
+    unsigned idau_region_valid : 1;
+    unsigned secure : 1;
+    unsigned nonsecure_readwrite_ok : 1;
+    unsigned nonsecure_read_ok : 1;
+#else
+    unsigned : 12;
+#endif
+    unsigned readwrite_ok : 1;
+    unsigned read_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned sau_region_valid : 1;
+#else
+    unsigned : 1;
+#endif
+    unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned sau_region : 8;
+#else
+    unsigned : 8;
+#endif
+    unsigned mpu_region : 8;
+
+#else /* __ARM_LITTLE_ENDIAN */
+    unsigned mpu_region : 8;
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned sau_region : 8;
+#else
+    unsigned : 8;
+#endif
+    unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned sau_region_valid : 1;
+#else
+    unsigned : 1;
+#endif
+    unsigned read_ok : 1;
+    unsigned readwrite_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+    unsigned nonsecure_read_ok : 1;
+    unsigned nonsecure_readwrite_ok : 1;
+    unsigned secure : 1;
+    unsigned idau_region_valid : 1;
+    unsigned idau_region : 8;
+#else
+    unsigned : 12;
+#endif
+#endif /*__ARM_LITTLE_ENDIAN */
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TT(void *__p) {
+  cmse_address_info_t __u;
+  __u.value = __builtin_arm_cmse_TT(__p);
+  return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTT(void *__p) {
+  cmse_address_info_t __u;
+  __u.value = __builtin_arm_cmse_TTT(__p);
+  return __u;
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTA(void *__p) {
+  cmse_address_info_t __u;
+  __u.value = __builtin_arm_cmse_TTA(__p);
+  return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTAT(void *__p) {
+  cmse_address_info_t __u;
+  __u.value = __builtin_arm_cmse_TTAT(__p);
+  return __u;
+}
+#endif
+
+#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p)))
+#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p)))
+
+#if __ARM_CMSE_SECURE_MODE
+#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p)))
+#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p)))
+#endif
+
+static void *__attribute__((__always_inline__))
+cmse_check_address_range(void *__pb, size_t __s, int __flags) {
+  uintptr_t __begin = (uintptr_t)__pb;
+  uintptr_t __end = __begin + __s - 1;
+
+  if (__end < __begin)
+    return NULL; /* wrap around check */
+
+  /* Check whether the range crosses a 32-bytes aligned address */
+  const int __single_check = (__begin ^ __end) < 0x20u;
+
+  /* execute the right variant of the TT instructions */
+  void *__pe = (void *)__end;
+  cmse_address_info_t __permb, __perme;
+  switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+  case 0:
+    __permb = cmse_TT(__pb);
+    __perme = __single_check ? __permb : cmse_TT(__pe);
+    break;
+  case CMSE_MPU_UNPRIV:
+    __permb = cmse_TTT(__pb);
+    __perme = __single_check ? __permb : cmse_TTT(__pe);
+    break;
+#if __ARM_CMSE_SECURE_MODE
+  case CMSE_MPU_NONSECURE:
+    __permb = cmse_TTA(__pb);
+    __perme = __single_check ? __permb : cmse_TTA(__pe);
+    break;
+  case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+    __permb = cmse_TTAT(__pb);
+    __perme = __single_check ? __permb : cmse_TTAT(__pe);
+    break;
+#endif
+  /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */
+  default:
+    return NULL;
+  }
+
+  /* check that the range does not cross MPU, SAU, or IDAU region boundaries */
+  if (__permb.value != __perme.value)
+    return NULL;
+#if !(__ARM_CMSE_SECURE_MODE)
+  /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */
+  if (__flags & CMSE_AU_NONSECURE)
+    return NULL;
+#endif
+
+  /* check the permission on the range */
+  switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+#if (__ARM_CMSE_SECURE_MODE)
+  case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+  case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL;
+
+  case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+    return __permb.flags.nonsecure_read_ok ? __pb : NULL;
+
+  case CMSE_AU_NONSECURE:
+    return __permb.flags.secure ? NULL : __pb;
+#endif
+  case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+  case CMSE_MPU_READWRITE:
+    return __permb.flags.readwrite_ok ? __pb : NULL;
+
+  case CMSE_MPU_READ:
+    return __permb.flags.read_ok ? __pb : NULL;
+
+  default:
+    return NULL;
+  }
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static int __attribute__((__always_inline__, __nodebug__))
+cmse_nonsecure_caller(void) {
+  return !((uintptr_t)__builtin_return_address(0) & 1);
+}
+
+#define cmse_nsfptr_create(p)                                                  \
+  __builtin_bit_cast(__typeof__(p),                                            \
+                     (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1))
+
+#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0)
+
+#endif /* __ARM_CMSE_SECURE_MODE */
+
+void __attribute__((__noreturn__)) cmse_abort(void);
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* (__ARM_FEATURE_CMSE & 0x1) */
+
+#endif /* __ARM_CMSE_H */

diff  --git a/clang/test/CodeGen/arm-cmse-nonsecure.c b/clang/test/CodeGen/arm-cmse-nonsecure.c
new file mode 100644
index 000000000000..2a483a71f593
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse-nonsecure.c
@@ -0,0 +1,52 @@
+// RUN: %clang  -mlittle-endian -target thumbv8m.base-eabi  -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang  -mbig-endian    -target thumbv8m.base-eabi  -emit-llvm -S -o - %s | FileCheck %s
+
+#include <arm_cmse.h>
+
+unsigned test_cmse_primitives(void *p) {
+// CHECK: define {{.*}} i32 @test_cmse_primitives
+  cmse_address_info_t tt_val, ttt_val;
+  unsigned sum;
+
+  tt_val = cmse_TT(p);
+  ttt_val = cmse_TTT(p);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: llvm.arm.cmse.tta
+// CHECK-NOT: llvm.arm.cmse.ttat
+
+  sum = tt_val.value;
+  sum += ttt_val.value;
+
+  sum += tt_val.flags.mpu_region;
+  sum += tt_val.flags.mpu_region_valid;
+  sum += tt_val.flags.read_ok;
+  sum += tt_val.flags.readwrite_ok;
+
+  return sum;
+}
+
+void *test_address_range(void *p) {
+// CHECK: define {{.*}} i8* @test_address_range
+  return cmse_check_address_range(p, 128, CMSE_MPU_UNPRIV
+                                        | CMSE_MPU_READWRITE
+                                        | CMSE_MPU_READ);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: llvm.arm.cmse.tta
+// CHECK-NOT: llvm.arm.cmse.ttat
+}
+
+typedef struct {
+    int x, y, z;
+} Point;
+
+void *test_pointed_object(void *p) {
+// CHECK: define {{.*}} i8* @test_pointed_object
+  Point *pt = (Point *)p;
+  cmse_check_pointed_object(pt, CMSE_MPU_READ);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: call i32 @llvm.arm.cmse.tta
+// CHECK-NOT: call i32 @llvm.arm.cmse.ttat
+}

diff  --git a/clang/test/CodeGen/arm-cmse-secure.c b/clang/test/CodeGen/arm-cmse-secure.c
new file mode 100644
index 000000000000..716887254e57
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse-secure.c
@@ -0,0 +1,66 @@
+// RUN: %clang -mlittle-endian -mcmse -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -mbig-endian    -mcmse -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+
+#include <arm_cmse.h>
+
+unsigned test_cmse_primitives(void *p) {
+// CHECK: define {{.*}} i32 @test_cmse_primitives
+  cmse_address_info_t tt_val, ttt_val;
+  cmse_address_info_t tta_val, ttat_val;
+  unsigned sum;
+
+  tt_val = cmse_TT(p);
+  ttt_val = cmse_TTT(p);
+  tta_val = cmse_TTA(p);
+  ttat_val = cmse_TTAT(p);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+
+  sum = tt_val.value;
+  sum += ttt_val.value;
+  sum += tta_val.value;
+  sum += ttat_val.value;
+
+  sum += tt_val.flags.mpu_region;
+  sum += tt_val.flags.sau_region;
+  sum += tt_val.flags.mpu_region_valid;
+  sum += tt_val.flags.sau_region_valid;
+  sum += tt_val.flags.read_ok;
+  sum += tt_val.flags.readwrite_ok;
+  sum += tt_val.flags.nonsecure_read_ok;
+  sum += tt_val.flags.nonsecure_readwrite_ok;
+  sum += tt_val.flags.secure;
+  sum += tt_val.flags.idau_region_valid;
+  sum += tt_val.flags.idau_region;
+
+  return sum;
+}
+
+void *test_address_range(void *p) {
+// CHECK: define {{.*}} i8* @test_address_range
+  return cmse_check_address_range(p, 128, CMSE_MPU_UNPRIV
+                                        | CMSE_MPU_NONSECURE
+                                        | CMSE_MPU_READWRITE);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+}
+
+typedef struct {
+  int x, y, z;
+} Point;
+
+void *test_pointed_object(void *p) {
+// CHECK: define {{.*}} i8* @test_pointed_object
+  Point *pt = (Point *)p;
+  cmse_check_pointed_object(pt, CMSE_NONSECURE
+                              | CMSE_MPU_READ
+                              | CMSE_AU_NONSECURE);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+}

diff  --git a/clang/test/CodeGen/arm-cmse.c b/clang/test/CodeGen/arm-cmse.c
new file mode 100644
index 000000000000..0f8247748ddc
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-none-eabi -O1 -emit-llvm %s -o - | FileCheck %s
+int test_cmse_TT(void *p){
+  return __builtin_arm_cmse_TT(p);
+  // CHECK: call i32 @llvm.arm.cmse.tt(i8* %{{.*}})
+}
+
+int test_cmse_TTT(void *p){
+  return __builtin_arm_cmse_TTT(p);
+  // CHECK: call i32 @llvm.arm.cmse.ttt(i8* %{{.*}})
+}
+
+int test_cmse_TTA(void *p){
+  return __builtin_arm_cmse_TTA(p);
+  // CHECK: call i32 @llvm.arm.cmse.tta(i8* %{{.*}})
+}
+
+int test_cmse_TTAT(void *p){
+  return __builtin_arm_cmse_TTAT(p);
+  // CHECK: call i32 @llvm.arm.cmse.ttat(i8* %{{.*}})
+}

diff  --git a/clang/test/Headers/arm-cmse-header-ns.c b/clang/test/Headers/arm-cmse-header-ns.c
new file mode 100644
index 000000000000..a6e63ef84149
--- /dev/null
+++ b/clang/test/Headers/arm-cmse-header-ns.c
@@ -0,0 +1,27 @@
+// RUN:     %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only        %s 2>&1 | FileCheck --check-prefix=CHECK-c %s
+// RUN: not %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only -x c++ %s 2>&1 | FileCheck --check-prefix=CHECK-cpp %s
+
+#include <arm_cmse.h>
+
+typedef void (*callback_t)(void);
+
+void func(callback_t fptr, void *p)
+{
+  cmse_TT(p);
+  cmse_TTT(p);
+  cmse_TT_fptr(fptr);
+  cmse_TTT_fptr(fptr);
+
+  cmse_TTA(p);
+  cmse_TTAT(p);
+  cmse_TTA_fptr(fptr);
+  cmse_TTAT_fptr(fptr);
+// CHECK-c: warning: implicit declaration of function 'cmse_TTA'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTAT'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTA_fptr'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTAT_fptr'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTA'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTAT'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTA_fptr'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTAT_fptr'
+}

diff  --git a/clang/test/Headers/arm-cmse-header.c b/clang/test/Headers/arm-cmse-header.c
new file mode 100644
index 000000000000..862572d8adcd
--- /dev/null
+++ b/clang/test/Headers/arm-cmse-header.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-eabi  -fsyntax-only -ffreestanding        %s -verify -mcmse
+// RUN: %clang_cc1 -triple thumbv8m.base-eabi  -fsyntax-only -ffreestanding -x c++ %s -verify -mcmse
+// expected-no-diagnostics
+
+#include <arm_cmse.h>
+
+typedef void (*callback_t)(void);
+
+void func(callback_t fptr, void *p)
+{
+  cmse_TT(p);
+  cmse_TTT(p);
+  cmse_TTA(p);
+  cmse_TTAT(p);
+
+  cmse_TT_fptr(fptr);
+  cmse_TTT_fptr(fptr);
+  cmse_TTA_fptr(fptr);
+  cmse_TTAT_fptr(fptr);
+}


        


More information about the cfe-commits mailing list