about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2024-08-28 11:21:19 +0100
committerYury Khrustalev <yury.khrustalev@arm.com>2024-10-14 13:16:03 +0100
commit9ecd8855cce2f6fac9fa1f1bb0d108c8d6329f1e (patch)
tree2eb5c085ba69ea836a9c359ce720e03e999bbdf4
parentd21abb82befc78bfb8200eff0d3144effcf4afba (diff)
downloadglibc-9ecd8855cce2f6fac9fa1f1bb0d108c8d6329f1e.tar.gz
glibc-9ecd8855cce2f6fac9fa1f1bb0d108c8d6329f1e.tar.xz
glibc-9ecd8855cce2f6fac9fa1f1bb0d108c8d6329f1e.zip
aarch64: Add GCS user-space allocation logic
Allocate GCS based on the stack size, this can be used for coroutines
(makecontext) and thread creation (if the kernel allows user allocated
GCS).
-rw-r--r--sysdeps/aarch64/Makefile3
-rw-r--r--sysdeps/aarch64/__alloc_gcs.c66
-rw-r--r--sysdeps/aarch64/aarch64-gcs.h36
3 files changed, 104 insertions, 1 deletions
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index 74479604f2..4b7f8a5c07 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -71,7 +71,8 @@ sysdep_headers += sys/ifunc.h
 sysdep_routines += \
   __mtag_tag_zero_region \
   __mtag_tag_region \
-  __arm_za_disable
+  __arm_za_disable \
+  __alloc_gcs
 
 tests += \
   tst-sme-jmp
diff --git a/sysdeps/aarch64/__alloc_gcs.c b/sysdeps/aarch64/__alloc_gcs.c
new file mode 100644
index 0000000000..62b7b6f396
--- /dev/null
+++ b/sysdeps/aarch64/__alloc_gcs.c
@@ -0,0 +1,66 @@
+/* AArch64 GCS allocation.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#ifndef __NR_map_shadow_stack
+# define __NR_map_shadow_stack 453
+#endif
+#ifndef SHADOW_STACK_SET_TOKEN
+# define SHADOW_STACK_SET_TOKEN (1UL << 0)
+# define SHADOW_STACK_SET_MARKER (1UL << 1)
+#endif
+
+static void *
+map_shadow_stack (void *addr, size_t size, unsigned long flags)
+{
+  return (void *) INLINE_SYSCALL_CALL (map_shadow_stack, addr, size, flags);
+}
+
+#define GCS_MAX_SIZE (1UL << 31)
+#define GCS_ALTSTACK_RESERVE 160
+
+void *
+__alloc_gcs (size_t stack_size, void **ss_base, size_t *ss_size)
+{
+  size_t size = (stack_size / 2 + GCS_ALTSTACK_RESERVE) & -8UL;
+  if (size > GCS_MAX_SIZE)
+    size = GCS_MAX_SIZE;
+
+  unsigned long flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN;
+  void *base = map_shadow_stack (NULL, size, flags);
+  if (base == (void *) -1)
+    return NULL;
+
+  *ss_base = base;
+  *ss_size = size;
+
+  uint64_t *gcsp = (uint64_t *) ((char *) base + size);
+  /* Skip end of GCS token.  */
+  gcsp--;
+  /* Verify GCS cap token.  */
+  gcsp--;
+  if (((uint64_t)gcsp & 0xfffffffffffff000) + 1 != *gcsp)
+    {
+      __munmap (base, size);
+      return NULL;
+    }
+  /* Return the target GCS pointer for context switch.  */
+  return gcsp + 1;
+}
diff --git a/sysdeps/aarch64/aarch64-gcs.h b/sysdeps/aarch64/aarch64-gcs.h
new file mode 100644
index 0000000000..cbd1065a5d
--- /dev/null
+++ b/sysdeps/aarch64/aarch64-gcs.h
@@ -0,0 +1,36 @@
+/* AArch64 GCS (Guarded Control Stack) declarations.
+   This file is part of the GNU C Library.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _AARCH64_GCS_H
+#define _AARCH64_GCS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+void *__alloc_gcs (size_t, void **, size_t *) attribute_hidden;
+
+static inline bool
+has_gcs (void)
+{
+  register unsigned long x16 asm ("x16") = 1;
+  asm ("hint	40" /* chkfeat x16 */ : "+r" (x16));
+  return x16 == 0;
+}
+
+#endif