From patchwork Sat Mar 23 17:32:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergey Bugaev X-Patchwork-Id: 87595 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6DFCA3858D33 for ; Sat, 23 Mar 2024 17:40:59 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) by sourceware.org (Postfix) with ESMTPS id 2C9F13858435 for ; Sat, 23 Mar 2024 17:35:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2C9F13858435 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2C9F13858435 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::133 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711215336; cv=none; b=Z9kjOqokD8p9ZpMb/399fhvsCa/zA4ExsdKM57F/e7hhF9ytBcywEszlriICicDIOWv2YS/DiJuRxsgmYaUo8x7k1pQLZ21NF/MVMauW4LqKVOHI5oswW0MzVXyV6d3lEk+JhyY6133uiGeSsWLJJIeE/IZIkxMwSRGc9a7e708= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711215336; c=relaxed/simple; bh=2Svubt2wXgYFVUnFpsoZK1ZRyxk/62Sd30kKyFZctv0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=q1va8f//N6R5/skACb0MrtrN9/nWDjoXQBLTkklaO5gVR0LedibyUpIPhmW5ghfyD6eBbS61Rh7tb5I8FJ6x2+DVbl+9ZIyd+hcPmnARB/Wh8Uk7XpvGrLXU0TD1W6H8xxni9UB6+H8R2SFhumfytZdiHM8AyAm9xf7mBesc5PI= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-lf1-x133.google.com with SMTP id 2adb3069b0e04-513d247e3c4so2875554e87.0 for ; Sat, 23 Mar 2024 10:35:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1711215329; x=1711820129; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9PlEzY53qDXnESrrCNwfcTKhTuk02hcxEilW+Y+osDg=; b=dqwvNb+fj9SvF5gp68om8kD8QAvxPYmNtJhVoycj1Y7lwxuKM4xwecrRZghYq8HpmB 3zRDms9ZJyElfAnLuCO8IsDHTznvm6aBD47Bo8I65Blt5Za5xs6d0qeU/klFHGzoIqcc MqQpkljCin1vDvm9LBCbyK02xUusdVS2/vqd9cINTbuGYrJOPoC7BPKNLTBCtu3MfCR9 QSoP8/9e2e42jvaYzDWh6jtLSCWFkge5yCw8P3nTRcnpadzUJ/NV/TzKH8yCYeCJLTbj mPN0m2PQD1MOw+WQ11kwIZ6UHfxQqxrehYX6RnSeb7KbA+qPbHtg0kq+rqw/WO+qZqHE DAGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711215329; x=1711820129; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9PlEzY53qDXnESrrCNwfcTKhTuk02hcxEilW+Y+osDg=; b=UNDldc6+P6N4A4WsHOZB/48OWnuYaXouR0+u6QcTWsixvtEbCVErVtFecYnNLV62yL DEM3Wl/KzNPp9E0hJT1gqmkyy5A2j14CpeQlPZRW2xPbQOUrlWwJbgMWUg/4EDtdI1FX 9Z2P07kYu2qdtCUDwnhMzkQL9z34PbBqm4+rc5y3Tlxk96nwx7/GAV6QB8dmx0SJYStS IlpT32JRgNfY8MvKXUOV1xg1RWF+NGPQvTMkOimMzKRUVzR68TKEapM0LAZU0xmrm4Ey QDIzpbYmdlLZl4LbcHBi1mmXwL5T+WHzsKHE+hQbD8qk7yAE6+fmWc2ICoahB0wuk4NU VK3g== X-Gm-Message-State: AOJu0YzM2SY/w5K2gv5iG4W9L+4QCudG7zZEpLlVTWmbontuHoWsAelt fpDbpk2Z7vNi4LTiM3KBjy+KDRi5hzOn65846/nhE3oL8HGI9e2vdK68+hcS X-Google-Smtp-Source: AGHT+IFiiFsHB8YEuigi6LItngKND9YRIr05ocNMn4Vf9Jmy8maf5kIrM2KzMJ4XRJLa0bmIVlR+6w== X-Received: by 2002:a05:6512:310d:b0:513:5e2f:6510 with SMTP id n13-20020a056512310d00b005135e2f6510mr691000lfb.31.1711215328940; Sat, 23 Mar 2024 10:35:28 -0700 (PDT) Received: from surface-pro-6.. (79-139-171-253.dynamic.spd-mgts.ru. [79.139.171.253]) by smtp.gmail.com with ESMTPSA id g20-20020ac25394000000b00513973dee6fsm361290lfh.150.2024.03.23.10.35.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 Mar 2024 10:35:28 -0700 (PDT) From: Sergey Bugaev To: libc-alpha@sourceware.org, bug-hurd@gnu.org Cc: Maxim Kuvyrkov , Luca Subject: [PATCH v2 17/20] hurd: Add an AArch64 signal implementation Date: Sat, 23 Mar 2024 20:32:58 +0300 Message-ID: <20240323173301.151066-18-bugaevc@gmail.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240323173301.151066-1-bugaevc@gmail.com> References: <20240323173301.151066-1-bugaevc@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Signed-off-by: Sergey Bugaev --- sysdeps/mach/hurd/aarch64/Makefile | 4 + sysdeps/mach/hurd/aarch64/bits/sigcontext.h | 96 ++++++ sysdeps/mach/hurd/aarch64/exc2signal.c | 149 +++++++++ sysdeps/mach/hurd/aarch64/intr-msg.h | 123 ++++++++ sysdeps/mach/hurd/aarch64/sigreturn.c | 127 ++++++++ sysdeps/mach/hurd/aarch64/trampoline.c | 325 ++++++++++++++++++++ 6 files changed, 824 insertions(+) create mode 100644 sysdeps/mach/hurd/aarch64/bits/sigcontext.h create mode 100644 sysdeps/mach/hurd/aarch64/exc2signal.c create mode 100644 sysdeps/mach/hurd/aarch64/intr-msg.h create mode 100644 sysdeps/mach/hurd/aarch64/sigreturn.c create mode 100644 sysdeps/mach/hurd/aarch64/trampoline.c diff --git a/sysdeps/mach/hurd/aarch64/Makefile b/sysdeps/mach/hurd/aarch64/Makefile index 9210d436..6cc831d6 100644 --- a/sysdeps/mach/hurd/aarch64/Makefile +++ b/sysdeps/mach/hurd/aarch64/Makefile @@ -22,3 +22,7 @@ endif ifeq ($(subdir),setjmp) gen-as-const-headers += signal-defines.sym endif + +ifeq ($(subdir),signal) +CFLAGS-sigreturn.c += -mgeneral-regs-only +endif diff --git a/sysdeps/mach/hurd/aarch64/bits/sigcontext.h b/sysdeps/mach/hurd/aarch64/bits/sigcontext.h new file mode 100644 index 00000000..163523fa --- /dev/null +++ b/sysdeps/mach/hurd/aarch64/bits/sigcontext.h @@ -0,0 +1,96 @@ +/* Machine-dependent signal context structure for GNU Hurd. AArch64 version. + Copyright (C) 1991-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 + . */ + +#ifndef _BITS_SIGCONTEXT_H +#define _BITS_SIGCONTEXT_H 1 + +#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H +# error "Never use directly; include instead." +#endif + +/* Signal handlers are actually called: + void handler (int sig, int code, struct sigcontext *scp); */ + +#include +#include + +/* State of this thread when the signal was taken. */ +struct sigcontext + { + /* These first members are machine-independent. */ + + int sc_onstack; /* Nonzero if running on sigstack. */ + __sigset_t sc_mask; /* Blocked signals to restore. */ + + /* MiG reply port this thread is using. */ + unsigned int sc_reply_port; + + /* Port this thread is doing an interruptible RPC on. */ + unsigned int sc_intr_port; + + /* Error code associated with this signal (interpreted as `error_t'). */ + int sc_error; + + /* Make sure the below members are properly aligned, and not packed + together with sc_error -- otherwise the layout won't match that of + aarch64_thread_state. */ + int sc_pad1; + + /* All following members are machine-dependent. The rest of this + structure is written to be laid out identically to: + { + struct aarch64_thread_state basic; + struct aarch64_float_state fpu; + } + trampoline.c knows this, so it must be changed if this changes. */ + +#define sc_aarch64_thread_state sc_x[0] /* Beginning of correspondence. */ + long sc_x[31]; + long sc_sp; + long sc_pc; + long sc_tpidr_el0; + long sc_cpsr; + +#define sc_aarch64_float_state sc_v[0] + __int128_t sc_v[32]; + long sc_fpsr; + long sc_fpcr; + }; + +/* Traditional BSD names for some members. */ +#define sc_fp sc_x[29] /* Frame pointer. */ +#define sc_ps sc_cpsr + + +/* The deprecated sigcode values below are passed as an extra, non-portable + argument to regular signal handlers. You should use SA_SIGINFO handlers + instead, which use the standard POSIX signal codes. */ + +/* Codes for SIGFPE. */ +#define FPE_INTOVF_TRAP 0x1 /* integer overflow */ +#define FPE_INTDIV_FAULT 0x2 /* integer divide by zero */ +#define FPE_FLTOVF_FAULT 0x3 /* floating overflow */ +#define FPE_FLTDIV_FAULT 0x4 /* floating divide by zero */ +#define FPE_FLTUND_FAULT 0x5 /* floating underflow */ +#define FPE_SUBRNG_FAULT 0x7 /* BOUNDS instruction failed */ +#define FPE_FLTDNR_FAULT 0x8 /* denormalized operand */ +#define FPE_FLTINX_FAULT 0x9 /* floating loss of precision */ +#define FPE_EMERR_FAULT 0xa /* mysterious emulation error 33 */ +#define FPE_EMBND_FAULT 0xb /* emulation BOUNDS instruction failed */ + +#endif /* bits/sigcontext.h */ diff --git a/sysdeps/mach/hurd/aarch64/exc2signal.c b/sysdeps/mach/hurd/aarch64/exc2signal.c new file mode 100644 index 00000000..7027bbf7 --- /dev/null +++ b/sysdeps/mach/hurd/aarch64/exc2signal.c @@ -0,0 +1,149 @@ +/* Translate Mach exception codes into signal numbers. AArch64 version. + Copyright (C) 1991-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 + . */ + +#include +#include +#include + +/* Translate the Mach exception codes, as received in an `exception_raise' RPC, + into a signal number and signal subcode. */ + +static void +exception2signal (struct hurd_signal_detail *detail, int *signo, int posix) +{ + detail->error = 0; + + switch (detail->exc) + { + default: + *signo = SIGIOT; + detail->code = detail->exc; + break; + + case EXC_BAD_ACCESS: + switch (detail->exc_code) + { + case KERN_INVALID_ADDRESS: + case KERN_MEMORY_FAILURE: + *signo = SIGSEGV; + detail->code = posix ? SEGV_MAPERR : detail->exc_subcode; + break; + + case KERN_PROTECTION_FAILURE: + case KERN_WRITE_PROTECTION_FAILURE: + *signo = SIGSEGV; + detail->code = posix ? SEGV_ACCERR : detail->exc_subcode; + break; + + case EXC_AARCH64_MTE: + *signo = SIGSEGV; + /* TODO: Should be SEGV_MTESERR */ + detail->code = posix ? SEGV_ACCERR : detail->exc_subcode; + break; + + case EXC_AARCH64_BTI: + *signo = SIGILL; + /* XXX: Consider adopting ILL_BTCFI from OpenBSD. */ + /* XXX: exc_subcode / signal code contains BTYPE */ + detail->code = posix ? ILL_ILLOPN : detail->exc_subcode; + break; + + case EXC_AARCH64_AL: + case EXC_AARCH64_AL_PC: + case EXC_AARCH64_AL_SP: + *signo = SIGBUS; + detail->code = posix ? BUS_ADRALN : detail->exc_subcode; + break; + + default: + *signo = SIGBUS; + detail->code = posix ? BUS_ADRERR : detail->exc_subcode; + break; + } + detail->error = detail->exc_code; + break; + + case EXC_BAD_INSTRUCTION: + *signo = SIGILL; + switch (detail->exc_code) + { + case EXC_AARCH64_SVC: + detail->code = posix ? ILL_ILLTRP : 0; + break; + + default: + detail->code = posix ? ILL_ILLOPC : 0; + break; + } + break; + + case EXC_ARITHMETIC: + *signo = SIGFPE; + switch (detail->exc_code) + { + case EXC_AARCH64_IDF: + detail->code = posix ? FPE_FLTIDO : 0; + break; + case EXC_AARCH64_IXF: + detail->code = posix ? FPE_FLTRES : FPE_FLTINX_FAULT; + break; + case EXC_AARCH64_UFF: + detail->code = posix ? FPE_FLTUND : FPE_FLTDNR_FAULT; + break; + case EXC_AARCH64_OFF: + detail->code = posix ? FPE_FLTOVF : FPE_FLTOVF_FAULT; + break; + case EXC_AARCH64_DZF: + detail->code = posix ? FPE_FLTDIV : FPE_FLTDIV_FAULT; + break; + case EXC_AARCH64_IOF: + /* NB: We used to send SIGILL here but we can't distinguish + POSIX vs. legacy with respect to what signal we send. */ + detail->code = posix ? FPE_FLTINV : 0 /*ILL_FPEOPR_FAULT*/; + break; + default: + detail->code = 0; + } + break; + + case EXC_EMULATION: + case EXC_SOFTWARE: + *signo = SIGEMT; + detail->code = 0; + break; + + + case EXC_BREAKPOINT: + *signo = SIGTRAP; + detail->code = posix ? TRAP_BRKPT : 0; + break; + } +} +libc_hidden_def (_hurd_exception2signal) + +void +_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo) +{ + exception2signal (detail, signo, 1); +} + +void +_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo) +{ + exception2signal (detail, signo, 0); +} diff --git a/sysdeps/mach/hurd/aarch64/intr-msg.h b/sysdeps/mach/hurd/aarch64/intr-msg.h new file mode 100644 index 00000000..b511d7d7 --- /dev/null +++ b/sysdeps/mach/hurd/aarch64/intr-msg.h @@ -0,0 +1,123 @@ +/* Machine-dependent details of interruptible RPC messaging. AArch64 version. + Copyright (C) 1995-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 + . */ + + +/* Note that we must mark OPTION and TIMEOUT as outputs of this operation, + to indicate that the signal thread might mutate them as part + of sending us to a signal handler. */ + +#define INTR_MSG_TRAP(msg, option, send_size, rcv_size, rcv_name, timeout, notify, cancel_p, intr_port_p) \ +({ \ + register uintptr_t /* error_t */ err asm ("x0"); \ + register uintptr_t option_x1 asm ("x1") = option; \ + register uintptr_t send_size_x2 asm ("x2") = send_size; \ + register uintptr_t rcv_size_x3 asm ("x3") = rcv_size; \ + register uintptr_t rcv_name_x4 asm ("x4") = rcv_name; \ + register uintptr_t timeout_x5 asm ("x5") = timeout; \ + register uintptr_t notify_x6 asm ("x6") = notify; \ + register void *msg_x9 asm ("x9") = msg; /* used by trampoline.c */ \ + asm volatile ("\n" \ + ".globl _hurd_intr_rpc_msg_about_to\n" \ + ".globl _hurd_intr_rpc_msg_setup_done\n" \ + ".globl _hurd_intr_rpc_msg_in_trap\n" \ + /* Clear x0 before we do the check for cancel below. This is to + detect x0 being set to non-zero (actually MACH_SEND_INTERRUPTED) + from the outside (namely, _hurdsig_abort_rpcs), which signals us + to skip the trap we were about to enter. */ \ + " mov %[err], #0\n" \ + "_hurd_intr_rpc_msg_about_to:\n" \ + /* We need to make a last check of cancel, in case we got interrupted + right before _hurd_intr_rpc_msg_about_to. */ \ + " ldr w8, %[cancel]\n" \ + " cbz w8, _hurd_intr_rpc_msg_do\n" \ + /* We got interrupted, note so and return EINTR. */ \ + " str wzr, %[intr_port]\n" \ + " mov %[err], %[eintr_lo]\n" \ + " movk %[err], %[eintr_hi], lsl 16\n" \ + " b _hurd_intr_rpc_msg_sp_restored\n" \ + "_hurd_intr_rpc_msg_do:\n" \ + /* Ok, prepare the mach_msg_trap arguments. We pass all the 7 args + in registers. */ \ + "_hurd_intr_rpc_msg_setup_done:\n" \ + /* From here on, it is safe to make us jump over the syscall. Now + check if we have been told to skip the syscall while running + the above. */ \ + " cbnz %[err], _hurd_intr_rpc_msg_in_trap\n" \ + /* Do the actual syscall. */ \ + " mov %[err], %[msg]\n" \ + " mov x8, #-25\n" \ + "_hurd_intr_rpc_msg_do_trap:\n" \ + " svc #0\n" /* status in %[err] */ \ + "_hurd_intr_rpc_msg_in_trap:\n" \ + "_hurd_intr_rpc_msg_sp_restored:\n" \ + : [err] "=r" (err), "+r" (option_x1), \ + [intr_port] "=m" (*intr_port_p), \ + "+r" (timeout_x5) \ + : [msg] "r" (msg_x9), "r" (send_size_x2), "r" (rcv_size_x3), \ + "r" (rcv_name_x4), "r" (notify_x6), \ + [cancel] "m" (*cancel_p), \ + [eintr_lo] "i" (EINTR & 0xffff), [eintr_hi] "i" (EINTR >> 16)); \ + option = option_x1; \ + timeout = timeout_x5; \ + err; \ +}) + +#include "hurdfault.h" + +/* This cannot be an inline function because it calls setjmp. */ +#define SYSCALL_EXAMINE(state, callno) \ +({ \ + int result; \ + unsigned int *p = (unsigned int *) (state)->pc - 4; \ + if (_hurdsig_catch_memory_fault (p)) \ + return 0; \ + if (result = (*p == 0xd4000001)) \ + /* The PC is just after a "svc #0" instruction. + This is a system call in progress; x8 holds the call number. */ \ + *(callno) = (state)->x[8]; \ + _hurdsig_end_catch_fault (); \ + result; \ +}) + + +/* This cannot be an inline function because it calls setjmp. */ +#define MSG_EXAMINE(state, msgid, rcvname, send_name, opt, tmout) \ +({ \ + int ret = 0; \ + const struct machine_thread_state *s = (state); \ + const mach_msg_header_t *msg = (const void *) s->x[0]; \ + *(opt) = s->x[1]; \ + *(rcvname) = s->x[4]; \ + *(tmout) = s->x[5]; \ + if (msg == 0) \ + { \ + *(send_name) = MACH_PORT_NULL; \ + *(msgid) = 0; \ + } \ + else \ + { \ + ret = _hurdsig_catch_memory_fault (msg) ? -1 : 0; \ + if (ret == 0) \ + { \ + *(send_name) = msg->msgh_remote_port; \ + *(msgid) = msg->msgh_id; \ + _hurdsig_end_catch_fault (); \ + } \ + } \ + ret; \ +}) diff --git a/sysdeps/mach/hurd/aarch64/sigreturn.c b/sysdeps/mach/hurd/aarch64/sigreturn.c new file mode 100644 index 00000000..c58b9c49 --- /dev/null +++ b/sysdeps/mach/hurd/aarch64/sigreturn.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1991-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 + . */ + +#include +#include +#include +#include + +/* This is run on the thread stack after restoring it, to be able to + unlock SS off sigstack. */ +void +__sigreturn2 (struct sigcontext *scp, + struct hurd_sigstate *ss) +{ + error_t err; + mach_port_t reply_port; + _hurd_sigstate_unlock (ss); + + /* Destroy the MiG reply port used by the signal handler, and restore the + reply port in use by the thread when interrupted. + + We cannot use the original reply port for our RPCs that we do here, since + we could unexpectedly receive/consume a reply message meant for the user + (in particular, msg_sig_post_reply), and also since we would deallocate + the port if *our* RPC fails, which we don't want to do since the user + still has the old name. And so, temporarily set MACH_PORT_DEAD as our + reply name, and make sure destroying the port is the very last RPC we + do. */ + reply_port = THREAD_GETMEM (THREAD_SELF, reply_port); + THREAD_SETMEM (THREAD_SELF, reply_port, MACH_PORT_DEAD); + if (__glibc_likely (MACH_PORT_VALID (reply_port))) + (void) __mach_port_mod_refs (__mach_task_self (), reply_port, + MACH_PORT_RIGHT_RECEIVE, -1); + THREAD_SETMEM (THREAD_SELF, reply_port, scp->sc_reply_port); + + /* Restore thread state. */ + err = __thread_set_self_state (AARCH64_FLOAT_STATE, + (thread_state_t) &scp->sc_aarch64_float_state, + AARCH64_FLOAT_STATE_COUNT); + assert_perror (err); + err = __thread_set_self_state (AARCH64_THREAD_STATE, + (thread_state_t) &scp->sc_aarch64_thread_state, + AARCH64_THREAD_STATE_COUNT); + assert_perror (err); + __builtin_unreachable (); +} + +int +__sigreturn (struct sigcontext *scp) +{ + struct hurd_sigstate *ss; + struct hurd_userlink *link = (void *) &scp[1]; + uintptr_t usp; + + if (__glibc_unlikely (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK))) + return __hurd_fail (EINVAL); + + ss = _hurd_self_sigstate (); + _hurd_sigstate_lock (ss); + + /* Remove the link on the `active resources' chain added by + _hurd_setup_sighandler. Its purpose was to make sure + that we got called; now we have, it is done. */ + _hurd_userlink_unlink (link); + + /* Restore the set of blocked signals, and the intr_port slot. */ + ss->blocked = scp->sc_mask; + ss->intr_port = scp->sc_intr_port; + + /* Check for pending signals that were blocked by the old set. */ + if (_hurd_sigstate_pending (ss) & ~ss->blocked) + { + /* There are pending signals that just became unblocked. Wake up the + signal thread to deliver them. But first, squirrel away SCP where + the signal thread will notice it if it runs another handler, and + arrange to have us called over again in the new reality. */ + ss->context = scp; + _hurd_sigstate_unlock (ss); + __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ()); + /* If a pending signal was handled, sig_post never returned. + If it did return, the pending signal didn't run a handler; + proceed as usual. */ + _hurd_sigstate_lock (ss); + ss->context = NULL; + } + + if (scp->sc_onstack) + ss->sigaltstack.ss_flags &= ~SS_ONSTACK; + + /* Copy the signal context onto the user's stack, to be able to release the + altstack (by unlocking sigstate). Note that unless an altstack is used, + the sigcontext will itself be located on the user's stack, so we may well + be overwriting it here (or later in __sigreturn2). */ + + usp = ALIGN_DOWN(scp->sc_sp - sizeof (struct sigcontext), 16); + memmove ((void *) usp, scp, sizeof (struct sigcontext)); + + /* Switch to the user's stack that we have just prepared, and call + __sigreturn2. Clobber "memory" to make sure GCC flushes the stack + setup to actual memory. */ + { + register uintptr_t usp_x0 asm("x0") = usp; + register struct hurd_sigstate *ss_x1 asm("x1") = ss; + + asm volatile ("mov sp, %0\n" + "b __sigreturn2" + :: "r" (usp_x0), "r" (ss_x1) + : "memory"); + __builtin_unreachable (); + } +} + +weak_alias (__sigreturn, sigreturn) diff --git a/sysdeps/mach/hurd/aarch64/trampoline.c b/sysdeps/mach/hurd/aarch64/trampoline.c new file mode 100644 index 00000000..4b301335 --- /dev/null +++ b/sysdeps/mach/hurd/aarch64/trampoline.c @@ -0,0 +1,325 @@ +/* Set thread_state for sighandler, and sigcontext to recover. AArch64 version. + Copyright (C) 1994-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 + . */ + +#include +#include +#include +#include +#include +#include +#include "hurdfault.h" +#include + + +/* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers. */ +static void fill_siginfo (siginfo_t *si, int signo, + const struct hurd_signal_detail *detail, + const struct machine_thread_all_state *state) +{ + si->si_signo = signo; + si->si_errno = detail->error; + si->si_code = detail->code; + + /* XXX We would need a protocol change for sig_post to include + * this information. */ + si->si_pid = -1; + si->si_uid = -1; + + /* Address of the faulting instruction or memory access. */ + if (detail->exc == EXC_BAD_ACCESS) + si->si_addr = (void *) detail->exc_subcode; + else + si->si_addr = (void *) state->basic.pc; + + /* XXX On SIGCHLD, this should be the exit status of the child + * process. We would need a protocol change for the proc server + * to send this information along with the signal. */ + si->si_status = 0; + + si->si_band = 0; /* SIGPOLL is not supported yet. */ + si->si_value.sival_int = 0; /* sigqueue() is not supported yet. */ +} + +/* Fill in a ucontext_t structure SA_SIGINFO-enabled handlers. */ +static void fill_ucontext (ucontext_t *uc, const struct sigcontext *sc) +{ + uc->uc_flags = 0; + uc->uc_link = NULL; + uc->uc_sigmask = sc->sc_mask; + uc->uc_stack.ss_sp = (__ptr_t) sc->sc_sp; + uc->uc_stack.ss_size = 0; + uc->uc_stack.ss_flags = 0; + + memcpy (&uc->uc_mcontext.gregs, &sc->sc_aarch64_thread_state, + sizeof (struct aarch64_thread_state)); + memcpy (&uc->uc_mcontext.fpregs, &sc->sc_aarch64_float_state, + sizeof (struct aarch64_float_state)); +} + +struct sigcontext * +_hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action, + __sighandler_t handler, + int signo, struct hurd_signal_detail *detail, + int rpc_wait, + struct machine_thread_all_state *state) +{ + void trampoline (void) attribute_hidden; + void rpc_wait_trampoline (void) attribute_hidden; + void *sigsp; + struct sigcontext *scp; + struct + { + union + { + int signo; + /* Make sure signo takes up a pointer-sized slot on the stack. + (This should already be the case considering the siginfop + pointer below, but better be explicit.) */ + void *_pointer_sized; + }; + union + { + /* Extra arguments for traditional signal handlers */ + struct + { + long int sigcode; + struct sigcontext *scp; /* Points to ctx, below. */ + } legacy; + + /* Extra arguments for SA_SIGINFO handlers */ + struct + { + siginfo_t *siginfop; /* Points to siginfo, below. */ + ucontext_t *uctxp; /* Points to uctx, below. */ + } posix; + }; + + void *_pad; + + /* NB: sigreturn assumes link is next to ctx. */ + struct sigcontext ctx; + struct hurd_userlink link; + ucontext_t ucontext; + siginfo_t siginfo; + } *stackframe; + + if (ss->context) + { + /* We have a previous sigcontext that sigreturn was about + to restore when another signal arrived. We will just base + our setup on that. */ + if (! _hurdsig_catch_memory_fault (ss->context)) + { + memcpy (&state->basic, &ss->context->sc_aarch64_thread_state, + sizeof (state->basic)); + memcpy (&state->fpu, &ss->context->sc_aarch64_float_state, + sizeof (state->fpu)); + state->set |= (1 << AARCH64_THREAD_STATE) | (1 << AARCH64_FLOAT_STATE); + } + } + + if (! machine_get_basic_state (ss->thread, state)) + return NULL; + + if ((action->sa_flags & SA_ONSTACK) + && !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK))) + { + sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size; + ss->sigaltstack.ss_flags |= SS_ONSTACK; + } + else + /* No red zone on aarch64-gnu. */ + sigsp = (void *) state->basic.sp; + + /* Push the arguments to call `trampoline' on the stack. + Note that user's SP doesn't strictly have to be 16-aligned, since + AArch64 only requires 16-alignment for the stack pointer when + making accesses relative to it. */ + sigsp = PTR_ALIGN_DOWN (sigsp - sizeof (*stackframe), 16); + stackframe = sigsp; + + _Static_assert ((void *) (&stackframe->_pad + 1) == (void *) &stackframe->ctx, + "trampoline expects no extra padding between " + "_pad and ctx"); + + if (_hurdsig_catch_memory_fault (stackframe)) + { + /* We got a fault trying to write the stack frame. + We cannot set up the signal handler. + Returning NULL tells our caller, who will nuke us with a SIGILL. */ + return NULL; + } + else + { + int ok; + + extern void _hurdsig_longjmp_from_handler (void *, jmp_buf, int); + + /* Add a link to the thread's active-resources list. We mark this as + the only user of the "resource", so the cleanup function will be + called by any longjmp which is unwinding past the signal frame. + The cleanup function (in sigunwind.c) will make sure that all the + appropriate cleanups done by sigreturn are taken care of. */ + stackframe->link.cleanup = &_hurdsig_longjmp_from_handler; + stackframe->link.cleanup_data = &stackframe->ctx; + stackframe->link.resource.next = NULL; + stackframe->link.resource.prevp = NULL; + stackframe->link.thread.next = ss->active_resources; + stackframe->link.thread.prevp = &ss->active_resources; + if (stackframe->link.thread.next) + stackframe->link.thread.next->thread.prevp + = &stackframe->link.thread.next; + ss->active_resources = &stackframe->link; + + /* Set up the sigcontext from the current state of the thread. */ + + scp = &stackframe->ctx; + scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0; + + /* struct sigcontext is laid out so that starting at sc_x[0] mimics a + struct aarch64_thread_state. */ + _Static_assert (offsetof (struct sigcontext, sc_aarch64_thread_state) + % __alignof__ (struct aarch64_thread_state) == 0, + "sc_aarch64_thread_state layout mismatch"); + memcpy (&scp->sc_aarch64_thread_state, + &state->basic, sizeof (state->basic)); + + /* struct sigcontext is laid out so that starting at sc_v[0] mimics a + struct aarch64_float_state. */ + _Static_assert (offsetof (struct sigcontext, sc_aarch64_float_state) + % __alignof__ (struct aarch64_float_state) == 0, + "sc_aarch64_float_state layout mismatch"); + ok = machine_get_state (ss->thread, state, AARCH64_FLOAT_STATE, + &state->fpu, &scp->sc_aarch64_float_state, + sizeof (state->fpu)); + + /* Set up the arguments for the signal handler. */ + stackframe->signo = signo; + if (action->sa_flags & SA_SIGINFO) + { + stackframe->posix.siginfop = &stackframe->siginfo; + stackframe->posix.uctxp = &stackframe->ucontext; + fill_siginfo (&stackframe->siginfo, signo, detail, state); + fill_ucontext (&stackframe->ucontext, scp); + } + else + { + if (detail->exc) + { + int nsigno; + _hurd_exception2signal_legacy (detail, &nsigno); + assert (nsigno == signo); + } + else + detail->code = 0; + + stackframe->legacy.sigcode = detail->code; + stackframe->legacy.scp = &stackframe->ctx; + } + + _hurdsig_end_catch_fault (); + + if (!ok) + return NULL; + } + + /* Modify the thread state to call the trampoline code on the new stack. */ + state->basic.sp = (uintptr_t) sigsp; + + if (rpc_wait) + { + /* The signalee thread was blocked in a mach_msg_trap system call, + still waiting for a reply. We will have it run the special + trampoline code which retries the message receive before running + the signal handler. + + To do this we change the OPTION argument (in x1) to enable only + message reception, since the request message has already been + sent. */ + + assert (state->basic.x[1] & MACH_RCV_MSG); + /* Disable the message-send, since it has already completed. The + calls we retry need only wait to receive the reply message. */ + state->basic.x[1] &= ~MACH_SEND_MSG; + + /* Limit the time to receive the reply message, in case the server + claimed that `interrupt_operation' succeeded but in fact the RPC + is hung. */ + state->basic.x[1] |= MACH_RCV_TIMEOUT; + state->basic.x[5] = _hurd_interrupted_rpc_timeout; + + state->basic.pc = (uintptr_t) rpc_wait_trampoline; + /* After doing the message receive, the trampoline code will need to + update the x0 value to be restored by sigreturn. To simplify + the assembly code, we pass the address of its slot in SCP to the + trampoline code in x21. */ + state->basic.x[21] = (uintptr_t) &scp->sc_x[0]; + } + else + state->basic.pc = (uintptr_t) trampoline; + + /* We pass the handler function to the trampoline code in x20. */ + state->basic.x[20] = (uintptr_t) handler; + + /* Clear pstate, notably reset BTYPE to 0. */ + state->basic.cpsr = 0; + + return scp; +} + +asm ("rpc_wait_trampoline:\n" + /* This is the entry point when we have an RPC reply message to receive + before running the handler. The MACH_MSG_SEND bit has already been + cleared in the OPTION argument in our x1. For our convenience, x21 + points to the sc_x[0] member of the sigcontext. + + When the sigcontext was saved, x0 was MACH_RCV_INTERRUPTED. To repeat + the message call, we need to restore the original message buffer + pointer; intr-msg.h keeps a backup copy of it in x9 specifically for + this purpose. */ + "mov x0, x9\n" + "svc #0\n" + /* Now the message receive has completed and the original caller of + the RPC (i.e. the code running when the signal arrived) needs to + see the final return value of the message receive in x0. So store + the new x0 value into the sc_x[0] member of the sigcontext (whose + address is in x21 to make this code simpler). */ + "str x0, [x21]\n" + + "trampoline:\n" + /* Entry point for running the handler normally. The arguments to the + handler function are on the top of the stack: + + [sp] SIGNO + [sp, #8] SIGCODE + [sp, #16] SCP + [sp, #24] _pad + + Pop them off to the registers, to pass as arguments to the handler. + */ + "ldp x0, x1, [sp], #16\n" + "ldr x2, [sp], #16\n" + /* Call handler (signo, sigcode, scp). Note that this is an indirect + call not using x16/x17, so this requires the signal handler to start + with a proper "bti c" marker. */ + "blr x20\n" + /* Call __sigreturn (), passing &CTX as SCP. CTX is on the top of + the stack. If __sigreturn () fails, we're in trouble. */ + "mov x0, sp\n" + "bl __sigreturn\n" + "udf #0xdead");