diff options
-rw-r--r-- | sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h | 48 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/ia64/syscall_cancel.S | 81 |
2 files changed, 129 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h b/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h new file mode 100644 index 0000000000..24f05f9759 --- /dev/null +++ b/sysdeps/unix/sysv/linux/ia64/cancellation-pc-check.h @@ -0,0 +1,48 @@ +/* Architecture specific bits for cancellation handling. + Copyright (C) 2023 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 + <http://www.gnu.org/licenses/>. */ + +#ifndef _NPTL_CANCELLATION_PC_CHECK +#define _NPTL_CANCELLATION_PC_CHECK 1 + +/* Check if the program counter (PC) from ucontext CTX is within the start and + then end boundary from the __syscall_cancel_arch bridge. Return TRUE if + the PC is within the boundary, meaning the syscall does not have any side + effects; or FALSE otherwise. */ +static bool +cancellation_pc_check (void *ctx) +{ + /* Both are defined in syscall_cancel.S for each architecture. */ + extern const char __syscall_cancel_arch_start[1]; + extern const char __syscall_cancel_arch_end[1]; + + uintptr_t sc_ip = ((struct sigcontext *) (ctx))->sc_ip; + uintptr_t cr_iip = sc_ip & ~0x3ull; + uintptr_t ri = sc_ip & 0x3ull; + + /* IA64 __syscall_cancel_arch issues the 'break 0x100000' on its own bundle, + and __syscall_cancel_arch_end points to end of the previous bundle. + To check if the syscall had any side-effects we need to check the slot + number. */ + if (cr_iip == (uintptr_t) __syscall_cancel_arch_end) + return ri == 0; + + return cr_iip >= (uintptr_t) __syscall_cancel_arch_start + && cr_iip < (uintptr_t) __syscall_cancel_arch_end; +} + +#endif diff --git a/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S b/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S new file mode 100644 index 0000000000..732bf60185 --- /dev/null +++ b/sysdeps/unix/sysv/linux/ia64/syscall_cancel.S @@ -0,0 +1,81 @@ +/* Cancellable syscall wrapper. Linux/IA64 version. + Copyright (C) 2023 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 + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include <descr-const.h> +#undef ret + +/* long int __syscall_cancel_arch (int *cancelhandling, long int nr, + long int arg1, long int arg2, long int arg3, + long int arg4, long int arg5, long int arg6) +*/ + +ENTRY (__syscall_cancel_arch) + .prologue ASM_UNW_PRLG_RP | ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE (8) + .mmi + .save ar.pfs, r41 + alloc r41=ar.pfs,8,3,8,0 + mov r15=r33 + .save rp, r40 + mov r40=b0 + .body + .mmi + mov r43=r34 + mov r44=r35 + mov r45=r36 + ;; + .mmi + mov r46=r37 + mov r47=r38 + mov r48=r39 + ;; + + .global __syscall_cancel_arch_start +__syscall_cancel_arch_start: + ;; + .mmi + nop 0 + ld4.acq r14=[r32] + nop 0 + ;; + .mib + nop 0 + tbit.z p6, p7=r14, TCB_CANCELED_BIT + .pred.safe_across_calls p1-p63 +(p7) br.call.dpnt.many b0 = __syscall_do_cancel# + .pred.safe_across_calls p1-p5,p16-p63 + ;; + + /* Due instruction bundle ia64 has the end marker before the syscall + instruction. Check IA64 ucontext_check_pc_boundary on how the PC + is checked. */ + .global __syscall_cancel_arch_end +__syscall_cancel_arch_end: + break 0x100000 + ;; + .mmi + cmp.ne p6, p7=-1, r10 + nop 0 + mov b0=r40 + ;; + .mib +(p7) sub r8=r0, r8 + mov ar.pfs=r41 + br.ret.sptk.many b0 + +END (__syscall_cancel_arch) |