diff options
author | Stafford Horne <shorne@gmail.com> | 2024-04-27 06:35:09 +0100 |
---|---|---|
committer | Stafford Horne <shorne@gmail.com> | 2024-05-03 18:28:18 +0100 |
commit | 643d9d38d50b32b5f20fb8ff5da17bff412821b6 (patch) | |
tree | 7c9b975e8e0df861663aca7a73489ff88704b0fc /sysdeps/unix/sysv | |
parent | b57adfa49b7ec75fad94548fb66fddc3bd92f457 (diff) | |
download | glibc-643d9d38d50b32b5f20fb8ff5da17bff412821b6.zip glibc-643d9d38d50b32b5f20fb8ff5da17bff412821b6.tar.gz glibc-643d9d38d50b32b5f20fb8ff5da17bff412821b6.tar.bz2 |
or1k: Add hard float support
This patch adds hardware floating point support to OpenRISC. Hardware
floating point toolchain builds are enabled by passing the machine
specific argument -mhard-float to gcc via CFLAGS. With this enabled GCC
generates floating point instructions for single-precision operations
and exports __or1k_hard_float__.
There are 2 main parts to this patch.
- Implement fenv functions to update the FPCSR flags keeping it in sync
with sfp (software floating point).
- Update machine context functions to store and restore the FPCSR
state.
*On mcontext_t ABI*
This patch adds __fpcsr to mcontext_t. This is an ABI change, but also
an ABI fix. The Linux kernel has always defined padding in mcontext_t
that space was missing from the glibc ABI. In Linux this unused space
has now been re-purposed for storing the FPCSR. This patch brings
OpenRISC glibc in line with the Linux kernel and other libc
implementation (musl).
Compatibility getcontext, setcontext, etc symbols have been added to
allow for binaries expecting the old ABI to continue to work.
*Hard float ABI*
The calling conventions and types do not change with OpenRISC hard-float
so glibc hard-float builds continue to use dynamic linker
/lib/ld-linux-or1k.so.1.
*Testing*
I have tested this patch both with hard-float and soft-float builds and
the test results look fine to me. Results are as follows:
Hard Float
# failures
FAIL: elf/tst-sprof-basic (Haven't figured out yet, not related to hard-float)
FAIL: gmon/tst-gmon-pie (PIE bug in or1k toolchain)
FAIL: gmon/tst-gmon-pie-gprof (PIE bug in or1k toolchain)
FAIL: iconvdata/iconv-test (timeout, passed when run manually)
FAIL: nptl/tst-cond24 (Timeout)
FAIL: nptl/tst-mutex10 (Timeout)
# summary
6 FAIL
4289 PASS
86 UNSUPPORTED
16 XFAIL
2 XPASS
# versions
Toolchain: or1k-smhfpu-linux-gnu
Compiler: gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
Binutils: GNU assembler version 2.42.0 (or1k-smhfpu-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
Linux: Linux buildroot 6.9.0-rc1-00008-g4dc70e1aadfa #112 SMP Sat Apr 27 06:43:11 BST 2024 openrisc GNU/Linux
Tester: shorne
Glibc: 2024-04-25 b62928f907 Florian Weimer x86: In ld.so, diagnose missing APX support in APX-only builds (origin/master, origin/HEAD)
Soft Float
# failures
FAIL: elf/tst-sprof-basic
FAIL: gmon/tst-gmon-pie
FAIL: gmon/tst-gmon-pie-gprof
FAIL: nptl/tst-cond24
FAIL: nptl/tst-mutex10
# summary
5 FAIL
4295 PASS
81 UNSUPPORTED
16 XFAIL
2 XPASS
# versions
Toolchain: or1k-smh-linux-gnu
Compiler: gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC)
Binutils: GNU assembler version 2.42.0 (or1k-smh-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324
Linux: Linux buildroot 6.9.0-rc1-00008-g4dc70e1aadfa #112 SMP Sat Apr 27 06:43:11 BST 2024 openrisc GNU/Linux
Tester: shorne
Glibc: 2024-04-25 b62928f907 Florian Weimer x86: In ld.so, diagnose missing APX support in APX-only builds (origin/master, origin/HEAD)
Documentation: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'sysdeps/unix/sysv')
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/Versions | 14 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/getcontext-common.S | 88 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/getcontext.S | 69 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/libc.abilist | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/makecontext.c | 49 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/setcontext-common.S | 120 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/setcontext.S | 102 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/swapcontext-common.S | 139 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/swapcontext.S | 109 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/sys/ucontext.h | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/or1k/ucontext_i.sym | 3 |
11 files changed, 480 insertions, 218 deletions
diff --git a/sysdeps/unix/sysv/linux/or1k/Versions b/sysdeps/unix/sysv/linux/or1k/Versions new file mode 100644 index 0000000..c1299de --- /dev/null +++ b/sysdeps/unix/sysv/linux/or1k/Versions @@ -0,0 +1,14 @@ +libc { + GLIBC_2.35 { + getcontext; + setcontext; + swapcontext; + makecontext; + } + GLIBC_2.40 { + getcontext; + setcontext; + swapcontext; + makecontext; + } +} diff --git a/sysdeps/unix/sysv/linux/or1k/getcontext-common.S b/sysdeps/unix/sysv/linux/or1k/getcontext-common.S new file mode 100644 index 0000000..9187749 --- /dev/null +++ b/sysdeps/unix/sysv/linux/or1k/getcontext-common.S @@ -0,0 +1,88 @@ +/* Save current context. OpenRISC common version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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/>. */ + +/* This common getcontext template helps define different + implementations using control macros. Before including + this file in another file define the following: + + __CONTEXT_FUNC_NAME + __CONTEXT_ENABLE_FPCSR + __CONTEXT_SIGMASK_OFFSET + */ + +/* int getcontext (ucontext_t *ucp) + + Returns 0 on success -1 and errno on failure. + */ + .text +ENTRY(__CONTEXT_FUNC_NAME) + /* Store r1, the stack pointer. */ + l.sw (UCONTEXT_MCONTEXT + 1*4)(r3), r1 + /* Store r2, the frame pointer. */ + l.sw (UCONTEXT_MCONTEXT + 2*4)(r3), r2 + /* Store r9, the link register. */ + l.sw (UCONTEXT_MCONTEXT + 9*4)(r3), r9 + /* Store r9 to reg[11] too, as we need two links for makecontext. */ + l.sw (UCONTEXT_MCONTEXT + 11*4)(r3), r9 + /* Store r10, the TLS register. */ + l.sw (UCONTEXT_MCONTEXT + 10*4)(r3), r10 + /* Store r14-r30 even, callee saved registers. */ + l.sw (UCONTEXT_MCONTEXT + 14*4)(r3), r14 + l.sw (UCONTEXT_MCONTEXT + 16*4)(r3), r16 + l.sw (UCONTEXT_MCONTEXT + 18*4)(r3), r18 + l.sw (UCONTEXT_MCONTEXT + 20*4)(r3), r20 + l.sw (UCONTEXT_MCONTEXT + 22*4)(r3), r22 + l.sw (UCONTEXT_MCONTEXT + 24*4)(r3), r24 + l.sw (UCONTEXT_MCONTEXT + 26*4)(r3), r26 + l.sw (UCONTEXT_MCONTEXT + 28*4)(r3), r28 + l.sw (UCONTEXT_MCONTEXT + 30*4)(r3), r30 + +#ifdef __CONTEXT_ENABLE_FPCSR +# ifdef __or1k_hard_float__ + /* Store the floating point state. */ + l.mfspr r4, r0, 20 + l.sw (MCONTEXT_FPCSR)(r3), r4 +# else + /* Store zero to indicate default rounding as per softfloat. */ + l.sw (MCONTEXT_FPCSR)(r3), r0 +# endif /* __or1k_hard_float__ */ +#endif /* __CONTEXT_ENABLE_FPCSR */ + + /* Get signal mask. */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + l.ori r6, r0, _NSIG8 + l.addi r5, r3, __CONTEXT_SIGMASK_OFFSET + l.ori r4, r0, 0 + l.ori r3, r0, SIG_BLOCK + l.ori r11, r0, SYS_ify (rt_sigprocmask) + /* Do the syscall. */ + l.sys 1 + l.nop + + /* if -4096 < ret < 0 holds, it's an error */ + l.sfgeui r11, 0xf001 + l.bf 1f + l.nop + + l.jr r9 + l.ori r11, r0, 0 + +1: l.j __syscall_error + l.ori r3, r11, 0 + +END(__CONTEXT_FUNC_NAME) diff --git a/sysdeps/unix/sysv/linux/or1k/getcontext.S b/sysdeps/unix/sysv/linux/or1k/getcontext.S index a25b377..da69e69 100644 --- a/sysdeps/unix/sysv/linux/or1k/getcontext.S +++ b/sysdeps/unix/sysv/linux/or1k/getcontext.S @@ -17,56 +17,35 @@ <https://www.gnu.org/licenses/>. */ #include <sysdep.h> +#include <shlib-compat.h> #include "ucontext_i.h" -/* int getcontext (ucontext_t *ucp) +#define __CONTEXT_FUNC_NAME __getcontext +#define __CONTEXT_ENABLE_FPCSR 1 +#define __CONTEXT_SIGMASK_OFFSET UCONTEXT_SIGMASK - Returns 0 on success -1 and errno on failure. - */ - .text -ENTRY(__getcontext) - /* Store r1, the stack pointer. */ - l.sw (UCONTEXT_MCONTEXT + 1*4)(r3), r1 - /* Store r2, the frame pointer. */ - l.sw (UCONTEXT_MCONTEXT + 2*4)(r3), r2 - /* Store r9, the link register. */ - l.sw (UCONTEXT_MCONTEXT + 9*4)(r3), r9 - /* Store r9 to reg[11] too, as we need two links for makecontext. */ - l.sw (UCONTEXT_MCONTEXT + 11*4)(r3), r9 - /* Store r10, the TLS register. */ - l.sw (UCONTEXT_MCONTEXT + 10*4)(r3), r10 - /* Store r14-r30 even, callee saved registers. */ - l.sw (UCONTEXT_MCONTEXT + 14*4)(r3), r14 - l.sw (UCONTEXT_MCONTEXT + 16*4)(r3), r16 - l.sw (UCONTEXT_MCONTEXT + 18*4)(r3), r18 - l.sw (UCONTEXT_MCONTEXT + 20*4)(r3), r20 - l.sw (UCONTEXT_MCONTEXT + 22*4)(r3), r22 - l.sw (UCONTEXT_MCONTEXT + 24*4)(r3), r24 - l.sw (UCONTEXT_MCONTEXT + 26*4)(r3), r26 - l.sw (UCONTEXT_MCONTEXT + 28*4)(r3), r28 - l.sw (UCONTEXT_MCONTEXT + 30*4)(r3), r30 +#include "getcontext-common.S" - /* Get signal mask. */ - /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ - l.ori r6, r0, _NSIG8 - l.addi r5, r3, UCONTEXT_SIGMASK - l.ori r4, r0, 0 - l.ori r3, r0, SIG_BLOCK - l.ori r11, r0, SYS_ify (rt_sigprocmask) - /* Do the syscall. */ - l.sys 1 - l.nop +versioned_symbol (libc, __getcontext, getcontext, GLIBC_2_40) - /* if -4096 < ret < 0 holds, it's an error */ - l.sfgeui r11, 0xf001 - l.bf 1f - l.nop +#if SHLIB_COMPAT (libc, GLIBC_2_35, GLIBC_2_40) - l.jr r9 - l.ori r11, r0, 0 +/* Define a compat version of getcontext for glibc's before the fpcsr + field was added to mcontext_t. The offset sigmask changed with this + introduction, the change was done because glibc's definition of + ucontext_t was initially defined incompatible with the Linux + definition of ucontext_t. We keep the compatability definition to + allow getcontext, setcontext and swapcontext to work in older + binaries. */ -1: l.j __syscall_error - l.ori r3, r11, 0 +# undef __CONTEXT_FUNC_NAME +# undef __CONTEXT_ENABLE_FPCSR +# undef __CONTEXT_SIGMASK_OFFSET +# define __CONTEXT_FUNC_NAME __getcontext_nofpcsr +# define __CONTEXT_SIGMASK_OFFSET (UCONTEXT_SIGMASK - 4) -END(__getcontext) -weak_alias(__getcontext, getcontext) +# include "getcontext-common.S" + +compat_symbol (libc, __getcontext_nofpcsr, getcontext, GLIBC_2_35) + +#endif diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index c40c843..959e59e 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2255,3 +2255,7 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.40 getcontext F +GLIBC_2.40 makecontext F +GLIBC_2.40 setcontext F +GLIBC_2.40 swapcontext F diff --git a/sysdeps/unix/sysv/linux/or1k/makecontext.c b/sysdeps/unix/sysv/linux/or1k/makecontext.c index fa6626e..7e131ba 100644 --- a/sysdeps/unix/sysv/linux/or1k/makecontext.c +++ b/sysdeps/unix/sysv/linux/or1k/makecontext.c @@ -16,6 +16,7 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#include <shlib-compat.h> #include <sysdep.h> #include <stdarg.h> #include <stdint.h> @@ -36,12 +37,11 @@ r1 : stack pointer r2 : frame pointer, set to NULL */ -void -__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +static void +do_makecontext (ucontext_t *ucp, void (*startcontext) (void), + void (*func) (void), int argc, va_list ap) { - extern void __startcontext (void); unsigned long int *sp; - va_list ap; int i; sp = (unsigned long int *) @@ -55,8 +55,8 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) /* Keep uc_link in r14. */ ucp->uc_mcontext.__gprs[14] = (uintptr_t) ucp->uc_link; - /* Return address points to function __startcontext. */ - ucp->uc_mcontext.__gprs[9] = (uintptr_t) &__startcontext; + /* Return address points to function startcontext. */ + ucp->uc_mcontext.__gprs[9] = (uintptr_t) startcontext; /* Frame pointer is null. */ ucp->uc_mcontext.__gprs[2] = (uintptr_t) 0; /* Restart in user-space starting at 'func'. */ @@ -64,14 +64,47 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) /* Set stack pointer. */ ucp->uc_mcontext.__gprs[1] = (uintptr_t) sp; - va_start (ap, argc); for (i = 0; i < argc; ++i) if (i < 6) ucp->uc_mcontext.__gprs[i + 3] = va_arg (ap, unsigned long int); else sp[i - 6] = va_arg (ap, unsigned long int); +} +void +__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + extern void __startcontext (void); + va_list ap; + + va_start (ap, argc); + do_makecontext (ucp, &__startcontext, func, argc, ap); va_end (ap); } -weak_alias (__makecontext, makecontext) +versioned_symbol (libc, __makecontext, makecontext, GLIBC_2_40); + +#if SHLIB_COMPAT (libc, GLIBC_2_35, GLIBC_2_40) + +/* Define a compat version of makecontext for glibc's before the fpcsr + field was added to mcontext_t. The offset sigmask changed with this + introduction, the change was done because glibc's definition of + ucontext_t was initially defined incompatible with the Linux + definition of ucontext_t. We keep the compatability definition to + allow getcontext, setcontext and swapcontext to work in older + binaries. */ + +void +__makecontext_nofpcsr (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + extern void __startcontext_nofpcsr (void); + va_list ap; + + va_start (ap, argc); + do_makecontext (ucp, &__startcontext_nofpcsr, func, argc, ap); + va_end (ap); +} + +compat_symbol (libc, __makecontext_nofpcsr, makecontext, GLIBC_2_35); + +#endif diff --git a/sysdeps/unix/sysv/linux/or1k/setcontext-common.S b/sysdeps/unix/sysv/linux/or1k/setcontext-common.S new file mode 100644 index 0000000..8a4f147 --- /dev/null +++ b/sysdeps/unix/sysv/linux/or1k/setcontext-common.S @@ -0,0 +1,120 @@ +/* Set current context. OpenRISC common version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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/>. */ + +/* This common setcontext and startcontext template helps define + different implementations using control macros. Before including + this file in another file define the following: + + __CONTEXT_FUNC_NAME + __CONTEXT_ENABLE_FPCSR + __CONTEXT_SIGMASK_OFFSET + __STARTCONTEXT_FUNC_NAME + */ + +/* int setcontext (const ucontext_t *ucp) */ + .text +ENTRY(__CONTEXT_FUNC_NAME) + l.ori r30, r3, 0 + + /* Restore signal mask. */ + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ + l.ori r6, r0, _NSIG8 + l.ori r5, r0, 0 + l.addi r4, r3, __CONTEXT_SIGMASK_OFFSET + l.ori r3, r0, SIG_SETMASK + l.ori r11, r0, SYS_ify (rt_sigprocmask) + /* Do the syscall. */ + l.sys 1 + l.nop + + /* if -4096 < ret < 0 holds, it's an error */ + l.sfgeui r11, 0xf001 + l.bf 1f + l.nop +#ifdef __CONTEXT_ENABLE_FPCSR +# ifdef __or1k_hard_float__ + /* Restore the floating point state. */ + l.lwz r28, (MCONTEXT_FPCSR)(r30) + l.mtspr r0, r28, 20 +# endif /* __or1k_hard_float__ */ +#endif /* __CONTEXT_ENABLE_FPCSR */ + /* Restore argument registers, for the makecontext case. */ + l.lwz r3, (UCONTEXT_MCONTEXT + 3*4)(r30) + l.lwz r4, (UCONTEXT_MCONTEXT + 4*4)(r30) + l.lwz r5, (UCONTEXT_MCONTEXT + 5*4)(r30) + l.lwz r6, (UCONTEXT_MCONTEXT + 6*4)(r30) + l.lwz r7, (UCONTEXT_MCONTEXT + 7*4)(r30) + l.lwz r8, (UCONTEXT_MCONTEXT + 8*4)(r30) + + /* Restore registers stored in getcontext. */ + l.lwz r1, (UCONTEXT_MCONTEXT + 1*4)(r30) + l.lwz r2, (UCONTEXT_MCONTEXT + 2*4)(r30) + l.lwz r9, (UCONTEXT_MCONTEXT + 9*4)(r30) + l.lwz r10, (UCONTEXT_MCONTEXT + 10*4)(r30) + l.lwz r11, (UCONTEXT_MCONTEXT + 11*4)(r30) + /* Restore r14-r30 even, callee saved registers. */ + l.lwz r14, (UCONTEXT_MCONTEXT + 14*4)(r30) + l.lwz r16, (UCONTEXT_MCONTEXT + 16*4)(r30) + l.lwz r18, (UCONTEXT_MCONTEXT + 18*4)(r30) + l.lwz r20, (UCONTEXT_MCONTEXT + 20*4)(r30) + l.lwz r22, (UCONTEXT_MCONTEXT + 22*4)(r30) + l.lwz r24, (UCONTEXT_MCONTEXT + 24*4)(r30) + l.lwz r26, (UCONTEXT_MCONTEXT + 26*4)(r30) + l.lwz r28, (UCONTEXT_MCONTEXT + 28*4)(r30) + l.lwz r30, (UCONTEXT_MCONTEXT + 30*4)(r30) + + l.jr r11 + l.ori r11, r0, 0 + +1: l.j __syscall_error + l.ori r3, r11, 0 + +END (__CONTEXT_FUNC_NAME) + + /* We add a NOP here because when the unwinder is looking for the + enclosing function of the link register (r9) address FDE lookup will + use '$r9 - 1' finding setcontext which is wrong. This is because in + makecontext we have set r9 to the start of &__startcontext. + + If this NOP did not exist the unwinder would repeatedly find + __setcontext's FDE in an infinite loop. Modifying/deleting the below + __startcontext's FDE has no help on this. */ + l.nop + +ENTRY(__STARTCONTEXT_FUNC_NAME) + + l.ori r3, r14, 0 + l.sfeq r3, r0 + /* If uc_link is not 0 resume there, otherwise exit. */ + l.bnf __CONTEXT_FUNC_NAME + l.nop + +#ifdef SHARED + /* Obtain a pointer to .got in r16 */ + l.jal 0x8 + l.movhi r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4) + l.ori r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0) + l.add r16, r16, r9 + l.lwz r16, got(exit)(r16) + l.jr r16 +#else + l.j exit +#endif + l.nop + +END(__STARTCONTEXT_FUNC_NAME) diff --git a/sysdeps/unix/sysv/linux/or1k/setcontext.S b/sysdeps/unix/sysv/linux/or1k/setcontext.S index d28a0ac..a49a5c5 100644 --- a/sysdeps/unix/sysv/linux/or1k/setcontext.S +++ b/sysdeps/unix/sysv/linux/or1k/setcontext.S @@ -16,93 +16,39 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#include <shlib-compat.h> #include <sysdep.h> #include "ucontext_i.h" -/* int setcontext (const ucontext_t *ucp) */ - .text -ENTRY(__setcontext) - l.ori r30, r3, 0 +#define __CONTEXT_FUNC_NAME __setcontext +#define __CONTEXT_ENABLE_FPCSR 1 +#define __CONTEXT_SIGMASK_OFFSET UCONTEXT_SIGMASK +#define __STARTCONTEXT_FUNC_NAME __startcontext - /* Restore signal mask. */ - /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ - l.ori r6, r0, _NSIG8 - l.ori r5, r0, 0 - l.addi r4, r3, UCONTEXT_SIGMASK - l.ori r3, r0, SIG_SETMASK - l.ori r11, r0, SYS_ify (rt_sigprocmask) - /* Do the syscall. */ - l.sys 1 - l.nop +#include "setcontext-common.S" - /* if -4096 < ret < 0 holds, it's an error */ - l.sfgeui r11, 0xf001 - l.bf 1f - l.nop +versioned_symbol (libc, __setcontext, setcontext, GLIBC_2_40) - /* Restore argument registers, for the makecontext case. */ - l.lwz r3, (UCONTEXT_MCONTEXT + 3*4)(r30) - l.lwz r4, (UCONTEXT_MCONTEXT + 4*4)(r30) - l.lwz r5, (UCONTEXT_MCONTEXT + 5*4)(r30) - l.lwz r6, (UCONTEXT_MCONTEXT + 6*4)(r30) - l.lwz r7, (UCONTEXT_MCONTEXT + 7*4)(r30) - l.lwz r8, (UCONTEXT_MCONTEXT + 8*4)(r30) +#if SHLIB_COMPAT (libc, GLIBC_2_35, GLIBC_2_40) - /* Restore registers stored in getcontext. */ - l.lwz r1, (UCONTEXT_MCONTEXT + 1*4)(r30) - l.lwz r2, (UCONTEXT_MCONTEXT + 2*4)(r30) - l.lwz r9, (UCONTEXT_MCONTEXT + 9*4)(r30) - l.lwz r10, (UCONTEXT_MCONTEXT + 10*4)(r30) - l.lwz r11, (UCONTEXT_MCONTEXT + 11*4)(r30) - /* Restore r14-r30 even, callee saved registers. */ - l.lwz r14, (UCONTEXT_MCONTEXT + 14*4)(r30) - l.lwz r16, (UCONTEXT_MCONTEXT + 16*4)(r30) - l.lwz r18, (UCONTEXT_MCONTEXT + 18*4)(r30) - l.lwz r20, (UCONTEXT_MCONTEXT + 20*4)(r30) - l.lwz r22, (UCONTEXT_MCONTEXT + 22*4)(r30) - l.lwz r24, (UCONTEXT_MCONTEXT + 24*4)(r30) - l.lwz r26, (UCONTEXT_MCONTEXT + 26*4)(r30) - l.lwz r28, (UCONTEXT_MCONTEXT + 28*4)(r30) - l.lwz r30, (UCONTEXT_MCONTEXT + 30*4)(r30) +/* Define a compat version of setcontext for glibc's before the fpcsr + field was added to mcontext_t. The offset sigmask changed with this + introduction, the change was done because glibc's definition of + ucontext_t was initially defined incompatible with the Linux + definition of ucontext_t. We keep the compatability definition to + allow getcontext, setcontext and swapcontext to work in older + binaries. */ - l.jr r11 - l.ori r11, r0, 0 +# undef __CONTEXT_FUNC_NAME +# undef __CONTEXT_ENABLE_FPCSR +# undef __CONTEXT_SIGMASK_OFFSET +# undef __STARTCONTEXT_FUNC_NAME +# define __CONTEXT_FUNC_NAME __setcontext_nofpcsr +# define __CONTEXT_SIGMASK_OFFSET (UCONTEXT_SIGMASK - 4) +# define __STARTCONTEXT_FUNC_NAME __startcontext_nofpcsr -1: l.j __syscall_error - l.ori r3, r11, 0 +# include "setcontext-common.S" -END (__setcontext) -weak_alias (__setcontext, setcontext) +compat_symbol (libc, __setcontext_nofpcsr, setcontext, GLIBC_2_35) - /* We add a NOP here because when the unwinder is looking for the - enclosing function of the link register (r9) address FDE lookup will - use '$r9 - 1' finding setcontext which is wrong. This is because in - makecontext we have set r9 to the start of &__startcontext. - - If this NOP did not exist the unwinder would repeatedly find - __setcontext's FDE in an infinite loop. Modifying/deleting the below - __startcontext's FDE has no help on this. */ - l.nop - -ENTRY(__startcontext) - - l.ori r3, r14, 0 - l.sfeq r3, r0 - /* If uc_link is not 0 resume there, otherwise exit. */ - l.bnf __setcontext - l.nop - -#ifdef SHARED - /* Obtain a pointer to .got in r16 */ - l.jal 0x8 - l.movhi r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4) - l.ori r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0) - l.add r16, r16, r9 - l.lwz r16, got(exit)(r16) - l.jr r16 -#else - l.j exit #endif - l.nop - -END(__startcontext) diff --git a/sysdeps/unix/sysv/linux/or1k/swapcontext-common.S b/sysdeps/unix/sysv/linux/or1k/swapcontext-common.S new file mode 100644 index 0000000..b7e2d4c --- /dev/null +++ b/sysdeps/unix/sysv/linux/or1k/swapcontext-common.S @@ -0,0 +1,139 @@ +/* Swap two contexts. OpenRISC version. + Copyright (C) 2022-2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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/>. */ + +/* This common swapcontext template helps define different + implementations using control macros. Before including this file + in another file define the following: + + __CONTEXT_FUNC_NAME + __CONTEXT_ENABLE_FPCSR + __CONTEXT_SIGMASK_OFFSET + */ + +/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ + .text +ENTRY(__CONTEXT_FUNC_NAME) + + /* Same as getcontext. */ + /* Store r1, the stack pointer. */ + l.sw (UCONTEXT_MCONTEXT + 1*4)(r3), r1 + /* Store r2, the frame pointer. */ + l.sw (UCONTEXT_MCONTEXT + 2*4)(r3), r2 + /* Store r9, the link register. */ + l.sw (UCONTEXT_MCONTEXT + 9*4)(r3), r9 + /* Store r9 to reg[11] too, as we need two links for makecontext. */ + l.sw (UCONTEXT_MCONTEXT + 11*4)(r3), r9 + /* Store r10, the TLS register. */ + l.sw (UCONTEXT_MCONTEXT + 10*4)(r3), r10 + /* Store r14-r30 even, callee saved registers. */ + l.sw (UCONTEXT_MCONTEXT + 14*4)(r3), r14 + l.sw (UCONTEXT_MCONTEXT + 16*4)(r3), r16 + l.sw (UCONTEXT_MCONTEXT + 18*4)(r3), r18 + l.sw (UCONTEXT_MCONTEXT + 20*4)(r3), r20 + l.sw (UCONTEXT_MCONTEXT + 22*4)(r3), r22 + l.sw (UCONTEXT_MCONTEXT + 24*4)(r3), r24 + l.sw (UCONTEXT_MCONTEXT + 26*4)(r3), r26 + l.sw (UCONTEXT_MCONTEXT + 28*4)(r3), r28 + l.sw (UCONTEXT_MCONTEXT + 30*4)(r3), r30 + +#ifdef __CONTEXT_ENABLE_FPCSR +# ifdef __or1k_hard_float__ + /* Store the floating point state. */ + l.mfspr r6, r0, 20 + l.sw (MCONTEXT_FPCSR)(r3), r6 +# else + /* Store zero to indicate default rounding as per softfloat. */ + l.sw (MCONTEXT_FPCSR)(r3), r0 +# endif /* __or1k_hard_float__ */ +#endif /* __CONTEXT_ENABLE_FPCSR */ + /* Store ucp to non-argument syscall preserved register. */ + l.ori r30, r4, 0 + + /* Get signal mask. */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + l.ori r6, r0, _NSIG8 + l.addi r5, r3, __CONTEXT_SIGMASK_OFFSET + l.ori r4, r0, 0 + l.ori r3, r0, SIG_BLOCK + l.ori r11, r0, SYS_ify (rt_sigprocmask) + /* Do the syscall. */ + l.sys 1 + l.nop + + /* if -4096 < ret < 0 holds, it's an error */ + l.sfgeui r11, 0xf001 + l.bf 1f + l.nop + + /* Same as setcontext. */ + + /* Restore signal mask. */ + /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ + l.ori r6, r0, _NSIG8 + l.ori r5, r0, 0 + l.addi r4, r30, __CONTEXT_SIGMASK_OFFSET + l.ori r3, r0, SIG_SETMASK + l.ori r11, r0, SYS_ify (rt_sigprocmask) + /* Do the syscall. */ + l.sys 1 + l.nop + + /* if -4096 < ret < 0 holds, it's an error */ + l.sfgeui r11, 0xf001 + l.bf 1f + l.nop + +#ifdef __CONTEXT_ENABLE_FPCSR +# ifdef __or1k_hard_float__ + /* Restore the floating point state. */ + l.lwz r28, (MCONTEXT_FPCSR)(r30) + l.mtspr r0, r28, 20 +# endif /* __or1k_hard_float__ */ +#endif /* __CONTEXT_ENABLE_FPCSR */ + + /* Restore argument registers, for the makecontext case. */ + l.lwz r3, (UCONTEXT_MCONTEXT + 3*4)(r30) + l.lwz r4, (UCONTEXT_MCONTEXT + 4*4)(r30) + l.lwz r5, (UCONTEXT_MCONTEXT + 5*4)(r30) + l.lwz r6, (UCONTEXT_MCONTEXT + 6*4)(r30) + l.lwz r7, (UCONTEXT_MCONTEXT + 7*4)(r30) + l.lwz r8, (UCONTEXT_MCONTEXT + 8*4)(r30) + + /* Restore registers stored in getcontext. */ + l.lwz r1, (UCONTEXT_MCONTEXT + 1*4)(r30) + l.lwz r2, (UCONTEXT_MCONTEXT + 2*4)(r30) + l.lwz r9, (UCONTEXT_MCONTEXT + 9*4)(r30) + l.lwz r10, (UCONTEXT_MCONTEXT + 10*4)(r30) + l.lwz r11, (UCONTEXT_MCONTEXT + 11*4)(r30) + l.lwz r14, (UCONTEXT_MCONTEXT + 14*4)(r30) + l.lwz r16, (UCONTEXT_MCONTEXT + 16*4)(r30) + l.lwz r18, (UCONTEXT_MCONTEXT + 18*4)(r30) + l.lwz r20, (UCONTEXT_MCONTEXT + 20*4)(r30) + l.lwz r22, (UCONTEXT_MCONTEXT + 22*4)(r30) + l.lwz r24, (UCONTEXT_MCONTEXT + 24*4)(r30) + l.lwz r26, (UCONTEXT_MCONTEXT + 26*4)(r30) + l.lwz r28, (UCONTEXT_MCONTEXT + 28*4)(r30) + l.lwz r30, (UCONTEXT_MCONTEXT + 30*4)(r30) + + l.jr r11 + l.ori r11, r0, 0 + +1: l.j __syscall_error + l.ori r3, r11, 0 + +END (__CONTEXT_FUNC_NAME) diff --git a/sysdeps/unix/sysv/linux/or1k/swapcontext.S b/sysdeps/unix/sysv/linux/or1k/swapcontext.S index d09651a..861c1e2 100644 --- a/sysdeps/unix/sysv/linux/or1k/swapcontext.S +++ b/sysdeps/unix/sysv/linux/or1k/swapcontext.S @@ -16,101 +16,36 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#include <shlib-compat.h> #include <sysdep.h> #include "ucontext_i.h" -/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */ - .text -ENTRY(__swapcontext) +#define __CONTEXT_FUNC_NAME __swapcontext +#define __CONTEXT_ENABLE_FPCSR 1 +#define __CONTEXT_SIGMASK_OFFSET UCONTEXT_SIGMASK - /* Same as getcontext. */ - /* Store r1, the stack pointer. */ - l.sw (UCONTEXT_MCONTEXT + 1*4)(r3), r1 - /* Store r2, the frame pointer. */ - l.sw (UCONTEXT_MCONTEXT + 2*4)(r3), r2 - /* Store r9, the link register. */ - l.sw (UCONTEXT_MCONTEXT + 9*4)(r3), r9 - /* Store r9 to reg[11] too, as we need two links for makecontext. */ - l.sw (UCONTEXT_MCONTEXT + 11*4)(r3), r9 - /* Store r10, the TLS register. */ - l.sw (UCONTEXT_MCONTEXT + 10*4)(r3), r10 - /* Store r14-r30 even, callee saved registers. */ - l.sw (UCONTEXT_MCONTEXT + 14*4)(r3), r14 - l.sw (UCONTEXT_MCONTEXT + 16*4)(r3), r16 - l.sw (UCONTEXT_MCONTEXT + 18*4)(r3), r18 - l.sw (UCONTEXT_MCONTEXT + 20*4)(r3), r20 - l.sw (UCONTEXT_MCONTEXT + 22*4)(r3), r22 - l.sw (UCONTEXT_MCONTEXT + 24*4)(r3), r24 - l.sw (UCONTEXT_MCONTEXT + 26*4)(r3), r26 - l.sw (UCONTEXT_MCONTEXT + 28*4)(r3), r28 - l.sw (UCONTEXT_MCONTEXT + 30*4)(r3), r30 +#include "swapcontext-common.S" - /* Store ucp to non-argument syscall preserved register. */ - l.ori r30, r4, 0 +versioned_symbol (libc, __swapcontext, swapcontext, GLIBC_2_40) - /* Get signal mask. */ - /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ - l.ori r6, r0, _NSIG8 - l.addi r5, r3, UCONTEXT_SIGMASK - l.ori r4, r0, 0 - l.ori r3, r0, SIG_BLOCK - l.ori r11, r0, SYS_ify (rt_sigprocmask) - /* Do the syscall. */ - l.sys 1 - l.nop +#if SHLIB_COMPAT (libc, GLIBC_2_35, GLIBC_2_40) - /* if -4096 < ret < 0 holds, it's an error */ - l.sfgeui r11, 0xf001 - l.bf 1f - l.nop +/* Define a compat version of swapcontext for glibc's before the fpcsr + field was added to mcontext_t. The offset sigmask changed with this + introduction, the change was done because glibc's definition of + ucontext_t was initially defined incompatible with the Linux + definition of ucontext_t. We keep the compatability definition to + allow getcontext, setcontext and swapcontext to work in older + binaries. */ - /* Same as setcontext. */ +# undef __CONTEXT_FUNC_NAME +# undef __CONTEXT_ENABLE_FPCSR +# undef __CONTEXT_SIGMASK_OFFSET +# define __CONTEXT_FUNC_NAME __swapcontext_nofpcsr +# define __CONTEXT_SIGMASK_OFFSET (UCONTEXT_SIGMASK - 4) - /* Restore signal mask. */ - /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */ - l.ori r6, r0, _NSIG8 - l.ori r5, r0, 0 - l.addi r4, r30, UCONTEXT_SIGMASK - l.ori r3, r0, SIG_SETMASK - l.ori r11, r0, SYS_ify (rt_sigprocmask) - /* Do the syscall. */ - l.sys 1 - l.nop +# include "swapcontext-common.S" - /* if -4096 < ret < 0 holds, it's an error */ - l.sfgeui r11, 0xf001 - l.bf 1f - l.nop +compat_symbol (libc, __swapcontext_nofpcsr, swapcontext, GLIBC_2_35) - /* Restore argument registers, for the makecontext case. */ - l.lwz r3, (UCONTEXT_MCONTEXT + 3*4)(r30) - l.lwz r4, (UCONTEXT_MCONTEXT + 4*4)(r30) - l.lwz r5, (UCONTEXT_MCONTEXT + 5*4)(r30) - l.lwz r6, (UCONTEXT_MCONTEXT + 6*4)(r30) - l.lwz r7, (UCONTEXT_MCONTEXT + 7*4)(r30) - l.lwz r8, (UCONTEXT_MCONTEXT + 8*4)(r30) - - /* Restore registers stored in getcontext. */ - l.lwz r1, (UCONTEXT_MCONTEXT + 1*4)(r30) - l.lwz r2, (UCONTEXT_MCONTEXT + 2*4)(r30) - l.lwz r9, (UCONTEXT_MCONTEXT + 9*4)(r30) - l.lwz r10, (UCONTEXT_MCONTEXT + 10*4)(r30) - l.lwz r11, (UCONTEXT_MCONTEXT + 11*4)(r30) - l.lwz r14, (UCONTEXT_MCONTEXT + 14*4)(r30) - l.lwz r16, (UCONTEXT_MCONTEXT + 16*4)(r30) - l.lwz r18, (UCONTEXT_MCONTEXT + 18*4)(r30) - l.lwz r20, (UCONTEXT_MCONTEXT + 20*4)(r30) - l.lwz r22, (UCONTEXT_MCONTEXT + 22*4)(r30) - l.lwz r24, (UCONTEXT_MCONTEXT + 24*4)(r30) - l.lwz r26, (UCONTEXT_MCONTEXT + 26*4)(r30) - l.lwz r28, (UCONTEXT_MCONTEXT + 28*4)(r30) - l.lwz r30, (UCONTEXT_MCONTEXT + 30*4)(r30) - - l.jr r11 - l.ori r11, r0, 0 - -1: l.j __syscall_error - l.ori r3, r11, 0 - -END (__swapcontext) -weak_alias (__swapcontext, swapcontext) +#endif diff --git a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h index b17e919..1b42859 100644 --- a/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h +++ b/sysdeps/unix/sysv/linux/or1k/sys/ucontext.h @@ -38,6 +38,7 @@ typedef struct unsigned long int __gprs[__NGREG]; unsigned long int __pc; unsigned long int __sr; + unsigned long int __fpcsr; } mcontext_t; /* Userlevel context. */ diff --git a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym index a8d4db0..45cd725 100644 --- a/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/or1k/ucontext_i.sym @@ -13,6 +13,7 @@ _NSIG8 (_NSIG / 8) -- Offsets of the fields in the ucontext_t structure. #define ucontext(member) offsetof (ucontext_t, member) #define stack(member) ucontext (uc_stack.member) +#define mcontext(member) ucontext (uc_mcontext.member) UCONTEXT_LINK ucontext (uc_link) UCONTEXT_STACK ucontext (uc_stack) @@ -23,4 +24,6 @@ STACK_SP stack (ss_sp) STACK_SIZE stack (ss_size) STACK_FLAGS stack (ss_flags) +MCONTEXT_FPCSR mcontext (__fpcsr) + UCONTEXT_SIZE sizeof (ucontext_t) |