diff mbox

[PATCHv2,1/8,V8M,arm-embedded] Add support for ARMv8-M's Security Extensions flag and intrinsics

Message ID 56FC0CB9.8080702@arm.com
State New
Headers show

Commit Message

Andre Vieira (lists) March 30, 2016, 5:28 p.m. UTC
Hi there,

Applied https://gcc.gnu.org/ml/gcc-patches/2015-12/msg02148.html on
embedded-5-branch using the included patch at revision r234582.


Cheers,
Andre

*** gcc ***
2016-03-30  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config.gcc (extra_headers): Added arm_cmse.h.
        * config/arm/arm-arches.def (armv8-m.base): Add FL_CMSE.
        (armv8-m.main): Likewise.
        (armv8-m.main+dsp): Likewise.
        * config/arm/arm-protos.h (arm_is_constant_pool_ref): Define
	FL_CMSE.
        * config/arm.c (arm_arch_cmse): New.
        (arm_option_override): New error for unsupported cmse target.
        * config/arm/arm.h (arm_arch_cmse): New.
        (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
        * config/arm/arm.opt (mcmse): New.
        * doc/invoke.texi (ARM Options): Add -mcmse.
        * doc/extend.texi (ACLE): Add CMSE.
        * config/arm/arm_cmse.h: New file.

*** libgcc ***
2016-03-30 Andre Vieira <andre.simoesdiasvieira@arm.com>
Thomas Preud'homme <thomas.preudhomme@arm.com>

 	* config/arm/cmse.c: Likewise.
 	* config/arm/t-arm (HAVE_CMSE): New.


*** gcc/testsuite ***
2016-03-30  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: New.
        * gcc.target/arm/cmse/cmse-1.c: New.
        * gcc.target/arm/cmse/cmse-12.c: New.
        * lib/target-supports.exp
        (check_effective_target_arm_cmse_ok): New.
diff mbox

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 9ee1024b6666d4d5f92d5dd28e763d37ee8324a7..4ec62db49f13642142b932d36f444f5ec9c74fd2 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -319,7 +319,7 @@  arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index d44179f290134eb2ec789dddd4b47aa5ccb74b42..8a7d8a3a3895aaf07a9b7e3c2f231357f8c81e21 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -56,8 +56,8 @@  ARM_ARCH("armv7-m", cortexm3,	7M,  FL_CO_PROC |	      FL_FOR_ARCH7M)
 ARM_ARCH("armv7e-m", cortexm4,  7EM, FL_CO_PROC |	      FL_FOR_ARCH7EM)
 ARM_ARCH("armv8-a", cortexa53,  8A,  FL_CO_PROC |             FL_FOR_ARCH8A)
 ARM_ARCH("armv8-a+crc",cortexa53, 8A,FL_CO_PROC | FL_CRC32  | FL_FOR_ARCH8A)
-ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,		      FL_FOR_ARCH8M_BASE)
-ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN, FL_CO_PROC |      FL_FOR_ARCH8M_MAIN)
-ARM_ARCH("armv8-m.main+dsp",cortexm7,8M_MAIN,FL_CO_PROC|FL_ARCH7EM|FL_FOR_ARCH8M_MAIN)
+ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,		      FL_FOR_ARCH8M_BASE |	FL_CMSE)
+ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN, FL_CO_PROC |      FL_FOR_ARCH8M_MAIN |	FL_CMSE)
+ARM_ARCH("armv8-m.main+dsp",cortexm7,8M_MAIN,FL_CO_PROC|FL_ARCH7EM|FL_FOR_ARCH8M_MAIN |	FL_CMSE)
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE, FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT)
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE, FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2)
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index f48366b2a77f59f91d339358912746f45de55a63..05acdfada28c619102059959bdcfa2a8223524ec 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -368,6 +368,7 @@  extern bool arm_is_constant_pool_ref (rtx);
 
 #define FL_IWMMXT     (1 << 29)	      /* XScale v2 or "Intel Wireless MMX technology".  */
 #define FL_IWMMXT2    (1 << 30)       /* "Intel Wireless MMX2 technology".  */
+#define FL_CMSE	      (1 << 31)	      /* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index d8d3ba5cba9807070989350644868fd88a98b4dc..7574064936e5217c8e553e7ab744cbe9320346d2 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -62,6 +62,13 @@  extern char arm_arch_name[];
 	  builtin_define ("__ARM_FEATURE_CRC32");	\
 	if (TARGET_32BIT)				\
 	  builtin_define ("__ARM_32BIT_STATE");		\
+	if (arm_arch8 && !arm_arch_notm)				\
+	  {								\
+	    if (arm_arch_cmse && use_cmse)				\
+	      builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);	\
+	    else							\
+	      builtin_define ("__ARM_FEATURE_CMSE");			\
+	  }								\
 	if (TARGET_ARM_FEATURE_LDREX)				\
 	  builtin_define_with_int_value (			\
 	    "__ARM_FEATURE_LDREX", TARGET_ARM_FEATURE_LDREX);	\
@@ -594,6 +601,9 @@  extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip support the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 778dac4ae014355c38e4312a81741859e5ce1daa..8c951490f0fa4eb5a5d14a1aaaaca75a51bdbe03 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -904,6 +904,9 @@  int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip support the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -2868,6 +2871,7 @@  arm_option_override (void)
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = (insn_flags & FL_CRC32) != 0;
   arm_m_profile_small_mul = (insn_flags & FL_SMALLMUL) != 0;
+  arm_arch_cmse = (insn_flags & FL_CMSE) != 0;
   if (arm_restrict_it == 2)
     arm_restrict_it = arm_arch8 && TARGET_THUMB2;
 
@@ -3219,6 +3223,9 @@  arm_option_override (void)
   if (TARGET_THUMB2)
     inline_asm_unified = 1;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index d4ff164c7ef43a71a380c20ba431db659ee30761..d536366e82a738ebd26f6f87b4ab2a90db349fa5 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@  mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..2afddb9b1394682b777edc8056551cf57e78df19
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,199 @@ 
+/* ARMV8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    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_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    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
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif
+
+#define cmse_TT_fptr(p) (cmse_TT_fptr_generic ((__cmse_fptr)p))
+
+typedef void (*__cmse_fptr)(void);
+
+#define CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT_fptr_generic (__cmse_fptr __p)
+CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (cmse_TTT_fptr_generic ((__cmse_fptr)p))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT_fptr_generic (__cmse_fptr __p)
+CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (cmse_TTA_fptr_generic ((__cmse_fptr)p))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA_fptr_generic (__cmse_fptr __p)
+CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (cmse_TTAT_fptr_generic ((__cmse_fptr)p))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT_fptr_generic (__cmse_fptr __p)
+CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+CMSE_TT_ASM (at)
+
+//TODO: diagnose use outside cmse_nonsecure_entry functions
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof (p)) cmse_check_address_range (p, sizeof (*p), f))
+
+#define cmse_nsfptr_create(p) ((typeof (p)) ((intptr_t) p & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) p & 1))
+
+#endif /* ifdef __ARM_FEATURE_CMSE.  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _GCC_ARM_CMSE_H.  */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 131d2154a1e3239d4d3dd2408410e8e7a456ab65..6d66405f68ae1a945931d48e6b09c0aaf71f23c2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -569,7 +569,8 @@  Objective-C and Objective-C++ Dialects}.
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
--mrestrict-it}
+-mrestrict-it
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -13512,6 +13513,10 @@  Print CPU tuning information as comment in assembler file.  This is
 an option used only for regression testing of the compiler and not
 intended for ordinary use in compiling code.  This option is disabled
 by default.
+
+@item -mcmse
+@opindex mcmse
+Generate secure code as per ARMv8-M Security Extensions.
 @end table
 
 @node AVR Options
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c3d4e9e934f4b1166d4d98383cf4ae8c3515117
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,68 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0cdc3cc82a61877572e3ba694c3d20f764d9a96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..43d46e5bd5b3a9b18c14ece2c87112727a25a162
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,45 @@ 
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 822b5b887c4583de49aa9eb680fbb04764f48b57..579d4884f5a1649d853b369ccf3f101086fe8447 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -2999,6 +2999,19 @@  proc check_effective_target_arm_thumb1_movt_ko {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M security extension is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("movt r0, #42");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..bea8fe4c61858d7f7e645dc62c420c11a6116121
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,110 @@ 
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+#include <stdint.h>
+
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    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 __ARM_FEATURE_CMSE & 2
+    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
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    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;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@ 
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
+ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif