summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/kvx
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux/kvx')
-rw-r--r--libc/sysdeps/linux/kvx/Makefile.arch2
-rw-r--r--libc/sysdeps/linux/kvx/bits/atomic.h212
-rw-r--r--libc/sysdeps/linux/kvx/bits/fcntl.h3
-rw-r--r--libc/sysdeps/linux/kvx/bits/shm.h87
-rw-r--r--libc/sysdeps/linux/kvx/bits/stat.h145
-rw-r--r--libc/sysdeps/linux/kvx/bits/uClibc_arch_features.h3
-rw-r--r--libc/sysdeps/linux/kvx/clone.S4
-rw-r--r--libc/sysdeps/linux/kvx/getcontext.S81
-rw-r--r--libc/sysdeps/linux/kvx/makecontext.c53
-rw-r--r--libc/sysdeps/linux/kvx/setcontext.S106
-rw-r--r--libc/sysdeps/linux/kvx/swapcontext.S63
-rw-r--r--libc/sysdeps/linux/kvx/sys/procfs.h13
-rw-r--r--libc/sysdeps/linux/kvx/sys/ucontext.h7
-rw-r--r--libc/sysdeps/linux/kvx/sys/user.h28
-rw-r--r--libc/sysdeps/linux/kvx/ucontext_i.sym28
15 files changed, 715 insertions, 120 deletions
diff --git a/libc/sysdeps/linux/kvx/Makefile.arch b/libc/sysdeps/linux/kvx/Makefile.arch
index 3ad290915..18f2118f6 100644
--- a/libc/sysdeps/linux/kvx/Makefile.arch
+++ b/libc/sysdeps/linux/kvx/Makefile.arch
@@ -8,3 +8,5 @@
CSRC-y := __syscall_error.c
CSRC-$(UCLIBC_LINUX_SPECIFIC) += cachectl.c
SSRC-y := setjmp.S bsd-setjmp.S bsd-_setjmp.S __longjmp.S clone.S vfork.S
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S swapcontext.S
diff --git a/libc/sysdeps/linux/kvx/bits/atomic.h b/libc/sysdeps/linux/kvx/bits/atomic.h
index 3c423e9ba..6e81e6704 100644
--- a/libc/sysdeps/linux/kvx/bits/atomic.h
+++ b/libc/sysdeps/linux/kvx/bits/atomic.h
@@ -1,6 +1,7 @@
-/* Copyright (C) 2010-2012 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 2023 Kalray Inc.
+
This file is part of the GNU C Library.
- Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -16,10 +17,15 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
+/* Mostly copied from aarch64 atomic.h */
+
#ifndef _KVX_BITS_ATOMIC_H
#define _KVX_BITS_ATOMIC_H
+#define typeof __typeof__
+
#include <stdint.h>
+#include <sysdep.h>
typedef int8_t atomic8_t;
typedef uint8_t uatomic8_t;
@@ -60,82 +66,130 @@ typedef uintmax_t uatomic_max_t;
# define atomic_write_barrier() __builtin_kvx_fence()
#endif
-/*
- * On kvx, we have a boolean compare and swap which means that the operation
- * returns only the success of operation.
- * If operation succeeds, this is simple, we just need to return the provided
- * old value. However, if it fails, we need to load the value to return it for
- * the caller. If the loaded value is different from the "old" provided by the
- * caller, we can return it since it will mean it failed.
- * However, if for some reason the value we read is equal to the old value
- * provided by the caller, we can't simply return it or the caller will think it
- * succeeded. So if the value we read is the same as the "old" provided by
- * the caller, we try again until either we succeed or we fail with a different
- * value than the provided one.
- */
-#define __cmpxchg(ptr, old, new, op_suffix, load_suffix) \
-({ \
- register unsigned long __rn __asm__("r62"); \
- register unsigned long __ro __asm__("r63"); \
- __asm__ __volatile__ ( \
- /* Fence to guarantee previous store to be committed */ \
- "fence\n" \
- /* Init "expect" with previous value */ \
- "copyd $r63 = %[rOld]\n" \
- ";;\n" \
- "1:\n" \
- /* Init "update" value with new */ \
- "copyd $r62 = %[rNew]\n" \
- ";;\n" \
- "acswap" #op_suffix " 0[%[rPtr]], $r62r63\n" \
- ";;\n" \
- /* if acswap succeeds, simply return */ \
- "cb.dnez $r62? 2f\n" \
- ";;\n" \
- /* We failed, load old value */ \
- "l" #op_suffix #load_suffix" $r63 = 0[%[rPtr]]\n" \
- ";;\n" \
- /* Check if equal to "old" one */ \
- "compd.ne $r62 = $r63, %[rOld]\n" \
- ";;\n" \
- /* If different from "old", return it to caller */ \
- "cb.deqz $r62? 1b\n" \
- ";;\n" \
- "2:\n" \
- : "+r" (__rn), "+r" (__ro) \
- : [rPtr] "r" (ptr), [rOld] "r" (old), [rNew] "r" (new) \
- : "memory"); \
- (__ro); \
-})
-
-#define cmpxchg(ptr, o, n) \
-({ \
- unsigned long __cmpxchg__ret; \
- switch (sizeof(*(ptr))) { \
- case 4: \
- __cmpxchg__ret = __cmpxchg((ptr), (o), (n), w, s); \
- break; \
- case 8: \
- __cmpxchg__ret = __cmpxchg((ptr), (o), (n), d, ); \
- break; \
- } \
- (__typeof(*(ptr))) (__cmpxchg__ret); \
-})
-
-#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
- cmpxchg((mem), (oldval), (newval))
-
-
-#define atomic_exchange_acq(mem, newval) \
-({ \
- unsigned long __aea__ret, __aea__old; \
- volatile __typeof((mem)) __aea__m = (mem); \
- do { \
- __aea__old = *__aea__m; \
- __aea__ret = atomic_compare_and_exchange_val_acq((mem), \
- (newval), (__aea__old));\
- } while (__aea__old != __aea__ret); \
- (__aea__old); \
-})
+#define __HAVE_64B_ATOMICS 1
+#define USE_ATOMIC_COMPILER_BUILTINS 1
+
+/* Compare and exchange.
+ For all "bool" routines, we return FALSE if exchange succesful. */
+
+# define __arch_compare_and_exchange_bool_8_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_16_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_32_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_bool_64_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ })
+
+# define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_16_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_32_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+# define __arch_compare_and_exchange_val_64_int(mem, newval, oldval, model) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
+ model, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+
+/* Compare and exchange with "acquire" semantics, ie barrier after. */
+
+# define atomic_compare_and_exchange_bool_acq(mem, new, old) \
+ __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+ mem, new, old, __ATOMIC_ACQUIRE)
+
+# define atomic_compare_and_exchange_val_acq(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, __ATOMIC_ACQUIRE)
+
+/* Compare and exchange with "release" semantics, ie barrier before. */
+
+# define atomic_compare_and_exchange_val_rel(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
+ mem, new, old, __ATOMIC_RELEASE)
+
+
+/* Atomic exchange (without compare). */
+
+# define __arch_exchange_8_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_16_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_32_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_64_int(mem, newval, model) \
+ __atomic_exchange_n (mem, newval, model)
+
+# define atomic_exchange_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_RELEASE)
+
+
+/* Atomically add value and return the previous (unincremented) value. */
+
+# define __arch_exchange_and_add_8_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_16_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_32_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_64_int(mem, value, model) \
+ __atomic_fetch_add (mem, value, model)
+
+# define atomic_exchange_and_add_acq(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
+ __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_and_add_rel(mem, value) \
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
#endif
diff --git a/libc/sysdeps/linux/kvx/bits/fcntl.h b/libc/sysdeps/linux/kvx/bits/fcntl.h
index ea0c59d09..79cd3f14e 100644
--- a/libc/sysdeps/linux/kvx/bits/fcntl.h
+++ b/libc/sysdeps/linux/kvx/bits/fcntl.h
@@ -227,3 +227,6 @@ extern ssize_t tee (int __fdin, int __fdout, size_t __len,
#endif
__END_DECLS
+
+/* Include generic Linux declarations. */
+#include <bits/fcntl-linux.h>
diff --git a/libc/sysdeps/linux/kvx/bits/shm.h b/libc/sysdeps/linux/kvx/bits/shm.h
new file mode 100644
index 000000000..bfb603499
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/bits/shm.h
@@ -0,0 +1,87 @@
+/*
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB
+ * in this tarball.
+ */
+
+#ifndef _SYS_SHM_H
+# error "Never include <bits/shm.h> directly; use <sys/shm.h> instead."
+#endif
+
+#include <bits/types.h>
+
+/* Permission flag for shmget. */
+#define SHM_R 0400 /* or S_IRUGO from <linux/stat.h> */
+#define SHM_W 0200 /* or S_IWUGO from <linux/stat.h> */
+
+/* Flags for `shmat'. */
+#define SHM_RDONLY 010000 /* attach read-only else read-write */
+#define SHM_RND 020000 /* round attach address to SHMLBA */
+#define SHM_REMAP 040000 /* take-over region on attach */
+
+/* Commands for `shmctl'. */
+#define SHM_LOCK 11 /* lock segment (root only) */
+#define SHM_UNLOCK 12 /* unlock segment (root only) */
+
+__BEGIN_DECLS
+
+/* Segment low boundary address multiple. */
+#define SHMLBA (__getpagesize () << 2)
+extern int __getpagesize (void) __THROW __attribute__ ((__const__));
+
+
+/* Type to count number of attaches. */
+typedef unsigned long int shmatt_t;
+
+/* Data structure describing a set of semaphores. */
+struct shmid_ds
+ {
+ struct ipc_perm shm_perm; /* operation permission struct */
+ size_t shm_segsz; /* size of segment in bytes */
+ __time_t shm_atime; /* time of last shmat() */
+ __time_t shm_dtime; /* time of last shmdt() */
+ __time_t shm_ctime; /* time of last change by shmctl() */
+ __pid_t shm_cpid; /* pid of creator */
+ __pid_t shm_lpid; /* pid of last shmop */
+ shmatt_t shm_nattch; /* number of current attaches */
+ unsigned long int __uclibc_unused1;
+ unsigned long int __uclibc_unused2;
+ };
+
+#ifdef __USE_MISC
+
+/* ipcs ctl commands */
+# define SHM_STAT 13
+# define SHM_INFO 14
+
+/* shm_mode upper byte flags */
+# define SHM_DEST 01000 /* segment will be destroyed on last detach */
+# define SHM_LOCKED 02000 /* segment will not be swapped */
+# define SHM_HUGETLB 04000 /* segment is mapped via hugetlb */
+# define SHM_NORESERVE 010000 /* don't check for reservations */
+
+struct shminfo
+ {
+ unsigned long int shmmax;
+ unsigned long int shmmin;
+ unsigned long int shmmni;
+ unsigned long int shmseg;
+ unsigned long int shmall;
+ unsigned long int __uclibc_unused1;
+ unsigned long int __uclibc_unused2;
+ unsigned long int __uclibc_unused3;
+ unsigned long int __uclibc_unused4;
+ };
+
+struct shm_info
+ {
+ int used_ids;
+ unsigned long int shm_tot; /* total allocated shm */
+ unsigned long int shm_rss; /* total resident shm */
+ unsigned long int shm_swp; /* total swapped shm */
+ unsigned long int swap_attempts;
+ unsigned long int swap_successes;
+ };
+
+#endif /* __USE_MISC */
+
+__END_DECLS
diff --git a/libc/sysdeps/linux/kvx/bits/stat.h b/libc/sysdeps/linux/kvx/bits/stat.h
new file mode 100644
index 000000000..716d86150
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/bits/stat.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _SYS_STAT_H
+# error "Never include <bits/stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#include <bits/align64bit.h>
+#include <bits/wordsize.h>
+#include <endian.h>
+
+/* Versions of the `struct stat' data structure. */
+#define _STAT_VER_LINUX_OLD 1
+#define _STAT_VER_KERNEL 1
+#define _STAT_VER_SVR4 2
+#define _STAT_VER_LINUX 3
+#define _STAT_VER _STAT_VER_LINUX /* The one defined below. */
+
+/* Versions of the `xmknod' interface. */
+#define _MKNOD_VER_LINUX 1
+#define _MKNOD_VER_SVR4 2
+#define _MKNOD_VER _MKNOD_VER_LINUX /* The bits defined below. */
+
+/*
+ * This struct is exactly the same with the stat64 one because kvx is 64 bit
+ */
+struct stat
+ {
+ unsigned long long st_dev; /* Device. */
+ unsigned long long st_ino; /* 32bit file serial number. */
+ unsigned int st_mode; /* File mode. */
+ unsigned int st_nlink; /* Link count. */
+ unsigned int st_uid; /* User ID of the file's owner. */
+ unsigned int st_gid; /* Group ID of the file's group.*/
+ unsigned long long st_rdev; /* Device number, if device. */
+ unsigned long long _pad1;
+ __off_t st_size; /* SIze of file, in bytes. */
+ int st_blksize; /* Optimal block size for I/O. */
+ int __pad2;
+ long long st_blocks; /* Number 512-byte blocks allocated */
+#if defined(__USE_MISC) || defined(__USE_XOPEN2K8)
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+ identifier 'timespec' to appear in the <sys/stat.h> header.
+ Therefore we have to handle the use of this header in strictly
+ standard-compliant sources special. */
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
+#else
+ long int st_atime; /* Time of last access. */
+ unsigned long int st_atime_nsec;
+ long int st_mtime; /* Time of last modification. */
+ unsigned long int st_mtime_nsec;
+ long int st_ctime; /* Time of last status change. */
+ unsigned long int st_ctime_nsec;
+#endif
+ unsigned int __uclibc_unused4;
+ unsigned int __uclibc_unused5;
+ } __ARCH_64BIT_ALIGNMENT__;
+
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+ {
+ unsigned long long st_dev; /* Device. */
+ unsigned long long st_ino; /* 32bit file serial number. */
+ unsigned int st_mode; /* File mode. */
+ unsigned int st_nlink; /* Link count. */
+ unsigned int st_uid; /* User ID of the file's owner. */
+ unsigned int st_gid; /* Group ID of the file's group.*/
+ unsigned long long st_rdev; /* Device number, if device. */
+ unsigned long long __pad3;
+ long long st_size; /* Size of file, in bytes. */
+ int st_blksize; /* Optimal block size for I/O. */
+ int __pad4;
+ long long st_blocks; /* Number 512-byte blocks allocated */
+# if defined(__USE_MISC) || defined(__USE_XOPEN2K8)
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+ identifier 'timespec' to appear in the <sys/stat.h> header.
+ Therefore we have to handle the use of this header in strictly
+ standard-compliant sources special. */
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+# else
+ long int st_atime; /* Time of last access. */
+ unsigned long int st_atime_nsec;
+ long int st_mtime; /* Time of last modification. */
+ unsigned long int st_mtime_nsec;
+ long int st_ctime; /* Time of last status change. */
+ unsigned long int st_ctime_nsec;
+# endif
+ unsigned int __uclibc_unused4;
+ unsigned int __uclibc_unused5;
+};
+#endif
+
+/* Tell code we have these members. */
+#define _STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported. */
+#define _STATBUF_ST_NSEC
+
+/* Encoding of the file mode. */
+
+#define __S_IFMT 0170000 /* These bits determine file type. */
+
+/* File types. */
+#define __S_IFDIR 0040000 /* Directory. */
+#define __S_IFCHR 0020000 /* Character device. */
+#define __S_IFBLK 0060000 /* Block device. */
+#define __S_IFREG 0100000 /* Regular file. */
+#define __S_IFIFO 0010000 /* FIFO. */
+#define __S_IFLNK 0120000 /* Symbolic link. */
+#define __S_IFSOCK 0140000 /* Socket. */
+
+/* POSIX.1b objects. Note that these macros always evaluate to zero. But
+ they do it by enforcing the correct use of the macros. */
+#define __S_TYPEISMQ(buf) ((buf)->st_mode - (buf)->st_mode)
+#define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode)
+#define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode)
+
+/* Protection bits. */
+
+#define __S_ISUID 04000 /* Set user ID on execution. */
+#define __S_ISGID 02000 /* Set group ID on execution. */
+#define __S_ISVTX 01000 /* Save swapped text after use (sticky). */
+#define __S_IREAD 0400 /* Read by owner. */
+#define __S_IWRITE 0200 /* Write by owner. */
+#define __S_IEXEC 0100 /* Execute by owner. */
+
+#ifdef __USE_ATFILE
+# define UTIME_NOW ((1l << 30) - 1l)
+# define UTIME_OMIT ((1l << 30) - 2l)
+#endif
diff --git a/libc/sysdeps/linux/kvx/bits/uClibc_arch_features.h b/libc/sysdeps/linux/kvx/bits/uClibc_arch_features.h
index 7aae2d7c3..ecccdc7bb 100644
--- a/libc/sysdeps/linux/kvx/bits/uClibc_arch_features.h
+++ b/libc/sysdeps/linux/kvx/bits/uClibc_arch_features.h
@@ -11,6 +11,9 @@
/* can your target use syscall6() for mmap ? */
#define __UCLIBC_MMAP_HAS_6_ARGS__
+/* does your target use statx */
+#define __UCLIBC_HAVE_STATX__
+
/* does your target align 64bit values in register pairs ? (32bit arches only) */
#undef __UCLIBC_SYSCALL_ALIGN_64BIT__
diff --git a/libc/sysdeps/linux/kvx/clone.S b/libc/sysdeps/linux/kvx/clone.S
index 71ea80a01..71553a4a9 100644
--- a/libc/sysdeps/linux/kvx/clone.S
+++ b/libc/sysdeps/linux/kvx/clone.S
@@ -59,10 +59,10 @@ ENTRY (__clone)
scall SYS_ify(clone)
;;
/* If 0, then we are the child */
- cb.deqz $r0, L(child_start)
+ cb.deqz $r0? L(child_start)
;;
/* Else we are the parent, and we need to check for errors */
- cb.dltz $r0, L(clone_error)
+ cb.dltz $r0? L(clone_error)
;;
/* No error ! Yeepa ! */
ret
diff --git a/libc/sysdeps/linux/kvx/getcontext.S b/libc/sysdeps/linux/kvx/getcontext.S
new file mode 100644
index 000000000..9440f67ce
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/getcontext.S
@@ -0,0 +1,81 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter@kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/*
+ * int getcontext (ucontext_t *ucp)
+ */
+ENTRY(__getcontext)
+ /* Save callee saved registers ($r14, $r18 - $r31)
+ * and some special registers */
+
+ /* Save the entire occtuple, although we only need $sp and $r14 */
+ so MCONTEXT_Q12[$r0] = $r12r13r14r15
+ get $r4 = $lc
+ ;;
+ /* Don't need to save veneer registers $r16 and $r17 */
+ sq (MCONTEXT_Q16 + 16)[$r0] = $r18r19
+ get $r5 = $le
+ ;;
+ so MCONTEXT_Q20[$r0] = $r20r21r22r23
+ get $r6 = $ls
+ ;;
+ so MCONTEXT_Q24[$r0] = $r24r25r26r27
+ get $r7 = $ra
+ ;;
+ so MCONTEXT_Q28[$r0] = $r28r29r30r31
+ get $r8 = $cs
+ ;;
+ so MCONTEXT_LC_LE_LS_RA[$r0] = $r4r5r6r7
+ /* Save ucp and $ra in callee saved registers because below we need to
+ * do a call to sigprocmask and afterwards we need to restore $ra. */
+ copyd $r20 = $r0
+ copyd $r21 = $r7
+ ;;
+ sd MCONTEXT_CS_SPC[$r0] = $r8
+
+ /* Prepare call to sigprocmask */
+ make $r0 = SIG_BLOCK
+ make $r1 = 0
+ ;;
+ /* $r20 points to the ucontext */
+ addd $r2 = $r20, UCONTEXT_SIGMASK
+ /* Already set the return value for when this is called in the context
+ * of swapcontext. Because when this context returns it should look
+ * like as if swapcontext returned with 0. */
+ sd MCONTEXT_Q0[$r20] = $r1
+ ;;
+ /* sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
+ call sigprocmask
+ ;;
+ /* Restore $ra to point to the caller of this function. So,
+ * __getcontext will return with -1 (set by __syscall_error) and an
+ * appropriate errno */
+ set $ra = $r21
+ ;;
+ /* Check return value of sigprocmask */
+ cb.deqz $r0 ? 1f
+ ;;
+ goto __syscall_error
+ ;;
+1:
+ /* Restore used callee saved registers */
+ lq $r20r21 = MCONTEXT_Q20[$r20]
+ ;;
+ /* Set return value */
+ make $r0 = 0
+ ret
+ ;;
+END(__getcontext)
+weak_alias(__getcontext, getcontext)
diff --git a/libc/sysdeps/linux/kvx/makecontext.c b/libc/sysdeps/linux/kvx/makecontext.c
new file mode 100644
index 000000000..a52eded9f
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/makecontext.c
@@ -0,0 +1,53 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter@kalrayinc.com>
+ */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+
+/* Number of arguments that go in registers. */
+#define NREG_ARGS 12
+
+/* Take a context previously prepared via getcontext() and set to
+ call func() with the given int only args. */
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __startcontext (void);
+ unsigned long *funcstack;
+ va_list vl;
+ unsigned long *regptr;
+ unsigned int reg;
+
+ /* Start at the top of stack. */
+ funcstack = (unsigned long *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ funcstack -= argc < NREG_ARGS ? 0 : argc - NREG_ARGS;
+ funcstack = (unsigned long *) (((uintptr_t) funcstack & -32L));
+
+ ucp->uc_mcontext.sc_regs.r12 = (unsigned long) funcstack;
+ /* Use $r20 and $r21 to pass some infos to __startcontext */
+ ucp->uc_mcontext.sc_regs.r20 = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.sc_regs.r21 = (unsigned long) func;
+ ucp->uc_mcontext.sc_regs.ra = (unsigned long) __startcontext;
+
+ va_start (vl, argc);
+
+ /* The first twelve arguments go into registers. */
+ regptr = &(ucp->uc_mcontext.sc_regs.r0);
+
+ for (reg = 0; (reg < argc) && (reg < NREG_ARGS); reg++)
+ *regptr++ = va_arg (vl, unsigned long);
+
+ /* And the remainder on the stack. */
+ for (; reg < argc; reg++)
+ *funcstack++ = va_arg (vl, unsigned long);
+
+ va_end (vl);
+}
+weak_alias (__makecontext, makecontext)
diff --git a/libc/sysdeps/linux/kvx/setcontext.S b/libc/sysdeps/linux/kvx/setcontext.S
new file mode 100644
index 000000000..7b91d21d9
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/setcontext.S
@@ -0,0 +1,106 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter@kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/*
+ * int setcontext (const ucontext_t *ucp)
+ */
+ENTRY(__setcontext)
+ get $r16 = $ra
+ addd $r12 = $r12, -32
+ ;;
+ /* Save ucp pointer and $ra on the stack because we can't trash
+ * any callee saved registers in case __setcontext returns */
+ sd 16[$r12] = $r16
+ ;;
+ sd 24[$r12] = $r0
+ ;;
+ /* Bring back the signal status. */
+ make $r0 = SIG_SETMASK
+ addd $r1 = $r0, UCONTEXT_SIGMASK
+ make $r2 = 0
+ ;;
+ /* sigprocmask(SIG_SETMASK, &(ucontext->uc_sigmask), NULL) */
+ call sigprocmask
+ ;;
+ /* Check return value of sigprocmask */
+ cb.deqz $r0 ? 1f
+ /* Normally __setcontext does not return. But in case of an error it
+ * returns with -1 and an appropriate errno */
+ ld $r16 = 16[$r12]
+ ;;
+ set $ra = $r16
+ addd $r12 = $r12, 32
+ ;;
+ goto __syscall_error
+ ;;
+1:
+ /* Get back the ucp pointer */
+ ld $r16 = 24[$r12]
+ /* Reset the stack pointer (we can trash $ra here, because we will
+ * never return to after __setcontext from this point onwards) */
+ addd $r12 = $r12, 32
+ ;;
+ /* Restore callee saved registers */
+ lq $r18r19 = (MCONTEXT_Q16 + 16)[$r16]
+ ;;
+ /* Setup $r20, $r21 for the __startcontext to work */
+ lo $r20r21r22r23 = MCONTEXT_Q20[$r16]
+ ;;
+ lo $r24r25r26r27 = MCONTEXT_Q24[$r16]
+ ;;
+ lo $r28r29r30r31 = MCONTEXT_Q28[$r16]
+ ;;
+ /* Restore special registers */
+ lo $r40r41r42r43 = MCONTEXT_LC_LE_LS_RA[$r16]
+ ;;
+ /* Now load argument registers */
+ lo $r0r1r2r3 = MCONTEXT_Q0[$r16]
+ set $lc = $r40
+ ;;
+ lo $r4r5r6r7 = MCONTEXT_Q4[$r16]
+ set $le = $r41
+ ;;
+ lo $r8r9r10r11 = MCONTEXT_Q8[$r16]
+ set $ls = $r42
+ ;;
+ /* Restore $sp */
+ ld $r12 = MCONTEXT_Q12[$r16]
+ /* Restore $ra which points to the $ra set by __getcontext or
+ * to__startcontext if __makecontext was called in between */
+ set $ra = $r43
+ ;;
+ ld $r40 = MCONTEXT_CS_SPC[$r16]
+ ;;
+ ld $r14 = (MCONTEXT_Q12 + 16)[$r16]
+ set $cs = $r40
+ ;;
+ ret
+ ;;
+END(setcontext)
+weak_alias(__setcontext, setcontext)
+
+ENTRY(__startcontext)
+ icall $r21
+ ;;
+ copyd $r0 = $r20
+ /* Check if the new context is 0 if so just call _exit */
+ cb.deqz $r20 ? 1f
+ ;;
+ goto __setcontext
+ ;;
+ /* This should never be reached otherwise kill the thread */
+1: goto _exit
+ ;;
+END(__startcontext)
diff --git a/libc/sysdeps/linux/kvx/swapcontext.S b/libc/sysdeps/linux/kvx/swapcontext.S
new file mode 100644
index 000000000..1abb6a8a8
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/swapcontext.S
@@ -0,0 +1,63 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2025 Kalray Inc.
+ * Author(s): Julian Vetter <jvetter@kalrayinc.com>
+ */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .text
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+ENTRY(swapcontext)
+ /* Make space on the stack to save all caller saved registers */
+ get $r16 = $ra
+ addd $r12 = $r12, -32
+ ;;
+
+ /* Save $ra on the stack */
+ sd (24)[$r12] = $r16
+ ;;
+ /* Save the arguments of swapcontext on the stack */
+ sq (8)[$r12] = $r0r1
+ ;;
+ call __getcontext
+ ;;
+
+ /* Save the return value of __getcontext in $r17 */
+ copyd $r17 = $r0
+
+ /* Restore $ra */
+ ld $r16 = (24)[$r12]
+ ;;
+ /* Restore arguments */
+ lq $r0r1 = (8)[$r12]
+ /* Readjust the stack pointer */
+ addd $r12 = $r12, 32
+ /* Also restore $ra */
+ set $ra = $r16
+ ;;
+
+ /* Exit if getcontext() failed */
+ cb.deqz $r17 ? 1f
+ ;;
+
+ /* Set the return value set by __syscall_error in __getcontext */
+ copyd $r0 = $r17
+ ret
+ ;;
+1:
+ /* Store the $sp and $ra in the context to be saved */
+ sd (MCONTEXT_Q12)[$r0] = $r12
+ ;;
+ sd (MCONTEXT_LC_LE_LS_RA + 24)[$r0] = $r16
+ copyd $r0 = $r1
+ goto __setcontext
+ ;;
+END(swapcontext)
diff --git a/libc/sysdeps/linux/kvx/sys/procfs.h b/libc/sysdeps/linux/kvx/sys/procfs.h
index bbbfb838e..b72322888 100644
--- a/libc/sysdeps/linux/kvx/sys/procfs.h
+++ b/libc/sysdeps/linux/kvx/sys/procfs.h
@@ -31,20 +31,15 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/user.h>
+#include <sys/ucontext.h>
-__BEGIN_DECLS
+#define ELF_NGREG NGREG
-/* Type for a general-purpose register. */
typedef unsigned long elf_greg_t;
-/* No FP registers for kvx. */
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct {} elf_fpregset_t;
-/* And the whole bunch of them. We could have used `struct
- pt_regs' directly in the typedef, but tradition says that
- the register set is an array, which does have some peculiar
- semantics, so leave it that way. */
-#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+__BEGIN_DECLS
/* Signal info. */
struct elf_siginfo
diff --git a/libc/sysdeps/linux/kvx/sys/ucontext.h b/libc/sysdeps/linux/kvx/sys/ucontext.h
index 548892389..6a30a09e2 100644
--- a/libc/sysdeps/linux/kvx/sys/ucontext.h
+++ b/libc/sysdeps/linux/kvx/sys/ucontext.h
@@ -12,17 +12,18 @@
#include <signal.h>
#include <bits/sigcontext.h>
+#define NGREG 70
+
/* Type for general register. */
typedef unsigned long greg_t;
-/* Number of general registers. */
-#define NGREG 64
+typedef struct sigcontext mcontext_t;
typedef struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
- struct sigcontext uc_mcontext;
+ mcontext_t uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
} ucontext_t;
diff --git a/libc/sysdeps/linux/kvx/sys/user.h b/libc/sysdeps/linux/kvx/sys/user.h
index 2e228ff19..c871f1a03 100644
--- a/libc/sysdeps/linux/kvx/sys/user.h
+++ b/libc/sysdeps/linux/kvx/sys/user.h
@@ -1,27 +1 @@
-/*
- * This file is subject to the terms and conditions of the LGPL V2.1
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2019 Kalray Inc.
- */
-
-#ifndef _SYS_USER_H
-#define _SYS_USER_H 1
-
-struct user_regs_struct
-{
- /* GPR */
- unsigned long long gpr_regs[64];
-
- /* SFR */
- unsigned long lc;
- unsigned long le;
- unsigned long ls;
- unsigned long ra;
-
- unsigned long cs;
- unsigned long spc;
-};
-
-#endif
+/* This file is not needed, but in practice gdb might try to include it. */
diff --git a/libc/sysdeps/linux/kvx/ucontext_i.sym b/libc/sysdeps/linux/kvx/ucontext_i.sym
new file mode 100644
index 000000000..d2b565332
--- /dev/null
+++ b/libc/sysdeps/linux/kvx/ucontext_i.sym
@@ -0,0 +1,28 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+SIG_BLOCK
+SIG_SETMASK
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+
+UCONTEXT_FLAGS ucontext (uc_flags)
+UCONTEXT_LINK ucontext (uc_link)
+UCONTEXT_STACK ucontext (uc_stack)
+UCONTEXT_MCONTEXT ucontext (uc_mcontext)
+UCONTEXT_SIGMASK ucontext (uc_sigmask)
+
+MCONTEXT_Q0 mcontext (sc_regs.r0)
+MCONTEXT_Q4 mcontext (sc_regs.r4)
+MCONTEXT_Q8 mcontext (sc_regs.r8)
+MCONTEXT_Q12 mcontext (sc_regs.r12)
+MCONTEXT_Q16 mcontext (sc_regs.r16)
+MCONTEXT_Q20 mcontext (sc_regs.r20)
+MCONTEXT_Q24 mcontext (sc_regs.r24)
+MCONTEXT_Q28 mcontext (sc_regs.r28)
+MCONTEXT_LC_LE_LS_RA mcontext (sc_regs.lc)
+MCONTEXT_CS_SPC mcontext (sc_regs.cs)