javed.absar created this revision.
javed.absar added reviewers: snidertm, dmgreen.
Herald added subscribers: kristof.beyls, mgorny.

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.


https://reviews.llvm.org/D62394

Files:
  include/clang/Basic/BuiltinsARM.def
  lib/Headers/CMakeLists.txt
  lib/Headers/arm_cmse.h
  test/CodeGen/arm-cmse-nonsecure.c
  test/CodeGen/arm-cmse-secure.c
  test/CodeGen/arm-cmse.c
  test/Headers/arm-cmse-header-ns.c
  test/Headers/arm-cmse-header.c

Index: test/Headers/arm-cmse-header.c
===================================================================
--- /dev/null
+++ test/Headers/arm-cmse-header.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-linux-gnueabihf  -fsyntax-only -ffreestanding %s -verify -mcmse
+// RUN: %clang_cc1 -triple thumbv8m.base-linux-gnueabihf  -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);
+}
Index: test/Headers/arm-cmse-header-ns.c
===================================================================
--- /dev/null
+++ test/Headers/arm-cmse-header-ns.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-linux-gnueabihf  -fsyntax-only -ffreestanding %s 2>&1 | FileCheck --check-prefix=CHECK-c %s
+// RUN: not %clang_cc1 -triple thumbv8m.base-linux-gnueabihf  -fsyntax-only -ffreestanding -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'
+}
Index: test/CodeGen/arm-cmse.c
===================================================================
--- /dev/null
+++ 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* %{{.*}})
+}
Index: test/CodeGen/arm-cmse-secure.c
===================================================================
--- /dev/null
+++ test/CodeGen/arm-cmse-secure.c
@@ -0,0 +1,66 @@
+// RUN: %clang -fvisibility=default -mlittle-endian -mcmse -Xclang -ffreestanding -target thumbv8m.base-linux-gnueabihf -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -fvisibility=default -mbig-endian    -mcmse -Xclang -ffreestanding -target thumbv8m.base-linux-gnueabihf -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
+}
Index: test/CodeGen/arm-cmse-nonsecure.c
===================================================================
--- /dev/null
+++ test/CodeGen/arm-cmse-nonsecure.c
@@ -0,0 +1,52 @@
+// RUN: %clang -fvisibility=default -mlittle-endian -Xclang -ffreestanding -target thumbv8m.base-linux-gnueabihf  -emit-llvm -S -o - %s | FileCheck %s
+// RUN-: %clang -fvisibility=default -mbig-endian    -Xclang -ffreestanding -target thumbv8m.base-linux-gnueabihf  -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
+}
Index: lib/Headers/arm_cmse.h
===================================================================
--- /dev/null
+++ lib/Headers/arm_cmse.h
@@ -0,0 +1,197 @@
+//===---- 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 <stdint.h>
+#include <stddef.h>
+
+#define __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 (__CMSE_SECURE_MODE)
+    unsigned idau_region:8;            /*bit 31-24*/
+    unsigned idau_region_valid:1;      /*bit 23-23*/
+    unsigned secure:1;                 /*bit 22-22*/
+    unsigned nonsecure_readwrite_ok:1; /*bit 21-21*/
+    unsigned nonsecure_read_ok:1;      /*bit 20-20*/
+#else
+    unsigned :12;                      /*bit 31-20*/
+#endif
+    unsigned readwrite_ok:1;           /*bit 19-19*/
+    unsigned read_ok:1;                /*bit 18-18*/
+#if (__CMSE_SECURE_MODE)
+    unsigned sau_region_valid:1;       /*bit 17-17*/
+#else
+    unsigned :1;                       /*bit 17-17*/
+#endif
+    unsigned mpu_region_valid:1;       /*bit 16-16*/
+#if (__CMSE_SECURE_MODE)
+    unsigned sau_region:8;             /*bit 15-08*/
+#else
+    unsigned :8;                       /*bit 15-08*/
+#endif
+    unsigned mpu_region:8;             /*bit 07-00*/
+
+#else /* __ARM_LITTLE_ENDIAN */
+    unsigned mpu_region:8;             /*bit 31-24*/
+#if (__CMSE_SECURE_MODE)
+    unsigned sau_region:8;             /*bit 23-16*/
+#else
+    unsigned :8;                       /*bit 23-16*/
+#endif
+    unsigned mpu_region_valid:1;       /*bit 15-15*/
+#if (__CMSE_SECURE_MODE)
+    unsigned sau_region_valid:1;       /*bit 14-14*/
+#else
+    unsigned :1;                       /*bit 14-14*/
+#endif
+    unsigned read_ok:1;                /*bit 13-13*/
+    unsigned readwrite_ok:1;           /*bit 12-12*/
+#if (__CMSE_SECURE_MODE)
+    unsigned nonsecure_read_ok:1;      /*bit 11-11*/
+    unsigned nonsecure_readwrite_ok:1; /*bit 10-10*/
+    unsigned secure:1;                 /*bit 09-09*/
+    unsigned idau_region_valid:1;      /*bit 08-08*/
+    unsigned idau_region:8;            /*bit 07-00*/
+#else
+    unsigned :12;                      /*bit 11-00*/
+#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 __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((void*)p))
+#define cmse_TTT_fptr(p) (cmse_TTT((void*)p))
+
+#if __CMSE_SECURE_MODE
+#define cmse_TTA_fptr(p) (cmse_TTA((void*)p))
+#define cmse_TTAT_fptr(p) (cmse_TTAT((void*)p))
+#endif
+
+static void* __attribute__((__always_inline__)) cmse_check_address_range(void *p, size_t s, int flags){
+  cmse_address_info_t permb, perme;
+  char *pb = (char *)p;
+  char *pe = pb + s -1;
+
+  if ((uintptr_t)pe < (uintptr_t)pb) return NULL; // wrap around check
+
+  // execute the right variant of the TT instructions
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 0x20u);
+
+  switch (flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+    case 0:
+      permb = cmse_TT(pb);
+      perme = singleCheck ? permb : cmse_TT(pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT(pb);
+      perme = singleCheck ? permb : cmse_TTT(pe);
+      break;
+#if __CMSE_SECURE_MODE
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA(pb);
+      perme = singleCheck ? permb : cmse_TTA(pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT(pb);
+      perme = singleCheck ? permb : cmse_TTAT(pe);
+      break;
+#endif
+    // if CMSE_NONSECURE is specified w/o __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 ! (__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 (__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 ? p : NULL;
+
+    case CMSE_MPU_READ|CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok ? p : NULL;
+
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure ? NULL : p;
+#endif
+    case CMSE_MPU_READ|CMSE_MPU_READWRITE:
+    case               CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok ? p : NULL;
+
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok ? p : NULL;
+
+   default:
+     return NULL;
+  }
+}
+
+#if __CMSE_SECURE_MODE
+static int __attribute__((__always_inline__, __nodebug__)) cmse_nonsecure_caller(void) {
+  return !((intptr_t)__builtin_return_address(0) & 1);
+}
+
+#define cmse_nsfptr_create(p)   ((__typeof__(p)) ((intptr_t) p & ~1))
+#define cmse_is_nsfptr(p)       (!((intptr_t) p & 1))
+#endif // __CMSE_SECURE_MODE
+
+void __attribute__((__noreturn__)) cmse_abort(void);
+#if defined(__cplusplus)
+}
+#endif
+#endif /* (__ARM_FEATURE_CMSE & 0x1) */
+#endif /* __ARM_CMSE_H */
Index: lib/Headers/CMakeLists.txt
===================================================================
--- lib/Headers/CMakeLists.txt
+++ lib/Headers/CMakeLists.txt
@@ -3,6 +3,7 @@
   altivec.h
   ammintrin.h
   arm_acle.h
+  arm_cmse.h
   armintr.h
   arm64intr.h
   avx2intrin.h
Index: include/clang/Basic/BuiltinsARM.def
===================================================================
--- include/clang/Basic/BuiltinsARM.def
+++ include/clang/Basic/BuiltinsARM.def
@@ -164,6 +164,12 @@
 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", "")
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to