mirror of
https://codeberg.org/guix/guix.git
synced 2026-01-25 12:05:19 -06:00
* gnu/packages/base.scm (glibc/hurd): Remove intr-msg-clobber.patch, add signal-fpe-exception.patch and xstate.patch. gnu/packages/patches/glibc-hurd-signal-fpe-exception.patch, gnu/packages/patches/glibc-hurd-xstate.patch : New patches * gnu/local.mk (dist_patch_DATA): Register them. Change-Id: Ib5b38f1fb8b43d76ec236232be8ff7552dad7422 Signed-off-by: Ludovic Courtès <ludo@gnu.org>
813 lines
28 KiB
Diff
813 lines
28 KiB
Diff
Cherry picked from glibc 2.42
|
|
|
|
6d6a6e2dd2 * hurd: save xstate during signal handling
|
|
8d54b428cf * hurd: Do not restore xstate when it is not initialized
|
|
0f2df19d95 * hurd: Do not check for xstate level if it was not initialized
|
|
|
|
From 6d6a6e2dd2133908e3f5cb8a2ed817ccb2a0bb06 Mon Sep 17 00:00:00 2001
|
|
From: Luca Dariz <luca@orpolo.org>
|
|
Date: Wed, 19 Mar 2025 18:11:18 +0100
|
|
Subject: [PATCH] hurd: save xstate during signal handling
|
|
|
|
* hurd/Makefile: add new tests
|
|
* hurd/test-sig-rpc-interrupted.c: check xstate save and restore in
|
|
the case where a signal is delivered to a thread which is waiting
|
|
for an rpc. This test implements the rpc interruption protocol used
|
|
by the hurd servers. It was so far passing on Debian thanks to the
|
|
local-intr-msg-clobber.diff patch, which is now obsolete.
|
|
* hurd/test-sig-xstate.c: check xstate save and restore in the case
|
|
where a signal is delivered to a running thread, making sure that
|
|
the xstate is modified in the signal handler.
|
|
* hurd/test-xstate.h: add helpers to test xstate
|
|
* sysdeps/mach/hurd/i386/bits/sigcontext.h: add xstate to the
|
|
sigcontext structure.
|
|
+ sysdeps/mach/hurd/i386/sigreturn.c: restore xstate from the saved
|
|
context
|
|
* sysdeps/mach/hurd/x86/trampoline.c: save xstate if
|
|
supported. Otherwise we fall back to the previous behaviour of
|
|
ignoring xstate.
|
|
* sysdeps/mach/hurd/x86_64/bits/sigcontext.h: add xstate to the
|
|
sigcontext structure.
|
|
* sysdeps/mach/hurd/x86_64/sigreturn.c: restore xstate from the saved
|
|
context
|
|
|
|
Signed-off-by: Luca Dariz <luca@orpolo.org>
|
|
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
|
Message-ID: <20250319171118.142163-1-luca@orpolo.org>
|
|
---
|
|
hurd/Makefile | 5 +
|
|
hurd/test-sig-rpc-interrupted.c | 185 +++++++++++++++++++++
|
|
hurd/test-sig-xstate.c | 94 +++++++++++
|
|
hurd/test-xstate.h | 40 +++++
|
|
sysdeps/mach/hurd/i386/bits/sigcontext.h | 2 +
|
|
sysdeps/mach/hurd/i386/sigreturn.c | 32 +++-
|
|
sysdeps/mach/hurd/x86/trampoline.c | 91 ++++++++--
|
|
sysdeps/mach/hurd/x86_64/bits/sigcontext.h | 2 +
|
|
sysdeps/mach/hurd/x86_64/sigreturn.c | 32 +++-
|
|
9 files changed, 458 insertions(+), 25 deletions(-)
|
|
create mode 100644 hurd/test-sig-rpc-interrupted.c
|
|
create mode 100644 hurd/test-sig-xstate.c
|
|
create mode 100644 hurd/test-xstate.h
|
|
|
|
diff --git a/hurd/Makefile b/hurd/Makefile
|
|
index cf70b8c65c..cbc3c23b1f 100644
|
|
--- a/hurd/Makefile
|
|
+++ b/hurd/Makefile
|
|
@@ -19,6 +19,11 @@ subdir := hurd
|
|
|
|
include ../Makeconfig
|
|
|
|
+tests := test-sig-xstate \
|
|
+ test-sig-rpc-interrupted
|
|
+$(objpfx)test-sig-xstate: $(shared-thread-library)
|
|
+$(objpfx)test-sig-rpc-interrupted: $(shared-thread-library) $(objdir)/hurd/libhurduser.so
|
|
+
|
|
headers = \
|
|
$(interface-headers) \
|
|
hurd.h \
|
|
diff --git a/hurd/test-sig-rpc-interrupted.c b/hurd/test-sig-rpc-interrupted.c
|
|
new file mode 100644
|
|
index 0000000000..a89d70e5a4
|
|
--- /dev/null
|
|
+++ b/hurd/test-sig-rpc-interrupted.c
|
|
@@ -0,0 +1,185 @@
|
|
+/* Test the state save/restore procedures during signal handling when an
|
|
+ interruptible RPC is restarted.
|
|
+
|
|
+ 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/>. */
|
|
+
|
|
+
|
|
+#include <assert.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include <mach/message.h>
|
|
+#include <mach/gnumach.h>
|
|
+#include <mach/mach_traps.h>
|
|
+#include <mach/mig_errors.h>
|
|
+#include <mach-shortcuts.h>
|
|
+#include <mach_init.h>
|
|
+#include <hurd/io.h>
|
|
+#include <hurd/io_reply.h>
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/xthread.h>
|
|
+
|
|
+#include "test-xstate.h"
|
|
+
|
|
+void handler (int signum, siginfo_t *info, void *context)
|
|
+{
|
|
+ printf ("signal %d setting a different CPU state\n", signum);
|
|
+ char buf3[XSTATE_BUFFER_SIZE];
|
|
+ memset (buf3, 0x77, XSTATE_BUFFER_SIZE);
|
|
+ SET_XSTATE (buf3);
|
|
+}
|
|
+
|
|
+static const mach_msg_type_t RetCodeCheck = {
|
|
+ .msgt_name = (unsigned char) MACH_MSG_TYPE_INTEGER_32,
|
|
+ .msgt_size = 32,
|
|
+ .msgt_number = 1,
|
|
+ .msgt_inline = TRUE,
|
|
+ .msgt_longform = FALSE,
|
|
+ .msgt_deallocate = FALSE,
|
|
+ .msgt_unused = 0
|
|
+};
|
|
+
|
|
+
|
|
+/* Helper thread to simulate a proper RPC interruption during dignal handling */
|
|
+void* fake_interruptor (void *arg)
|
|
+{
|
|
+ int err;
|
|
+ sigset_t ss;
|
|
+ TEST_COMPARE (sigemptyset (&ss), 0);
|
|
+ TEST_COMPARE (sigaddset (&ss, SIGUSR1), 0);
|
|
+ TEST_COMPARE (sigprocmask (SIG_BLOCK, &ss, NULL), 0);
|
|
+
|
|
+ struct {
|
|
+ mach_msg_header_t Head;
|
|
+ } request;
|
|
+ mach_port_t rxport = *((mach_port_t*)arg);
|
|
+ err = mach_msg (&request.Head, MACH_RCV_MSG, 0, sizeof (request), rxport,
|
|
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+ TEST_COMPARE (request.Head.msgh_bits, 0x1112);
|
|
+ TEST_COMPARE (request.Head.msgh_size, sizeof (request.Head));
|
|
+ TEST_COMPARE (request.Head.msgh_id, 33000);
|
|
+
|
|
+ mig_reply_header_t reply;
|
|
+ reply.Head = request.Head;
|
|
+ reply.Head.msgh_id += 100;
|
|
+ reply.RetCodeType = RetCodeCheck;
|
|
+ reply.RetCode = KERN_SUCCESS;
|
|
+ err = mach_msg (&reply.Head, MACH_SEND_MSG, sizeof (reply), 0, MACH_PORT_NULL,
|
|
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+/* Helper thread to send a signal to the main thread in the middle of
|
|
+ * an interruptible rpc */
|
|
+void* signal_sender (void *arg)
|
|
+{
|
|
+ int err;
|
|
+ sigset_t ss;
|
|
+ TEST_COMPARE (sigemptyset (&ss), 0);
|
|
+ TEST_COMPARE (sigaddset (&ss, SIGUSR1), 0);
|
|
+ TEST_COMPARE (sigprocmask (SIG_BLOCK, &ss, NULL), 0);
|
|
+
|
|
+ /* Receive the first request, we won't answer to this. */
|
|
+ struct {
|
|
+ mach_msg_header_t head;
|
|
+ char data[64];
|
|
+ } m1, m2;
|
|
+ mach_port_t rxport = *((mach_port_t*)arg);
|
|
+ memset (&m1, 0, sizeof (m1));
|
|
+ memset (&m2, 0, sizeof (m2));
|
|
+ err = mach_msg (&m1.head, MACH_RCV_MSG, 0, sizeof (m1), rxport,
|
|
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ /* interrupt the ongoing rpc with a signal, using the
|
|
+ * interruptible rpc protocol */
|
|
+ pthread_t thintr = xpthread_create (NULL, fake_interruptor, arg);
|
|
+ TEST_COMPARE (kill (getpid (), SIGUSR1), 0);
|
|
+ xpthread_join (thintr);
|
|
+
|
|
+ /* Complete the interruption by sending EINTR */
|
|
+ mig_reply_header_t reply;
|
|
+ reply.Head = m1.head;
|
|
+ reply.Head.msgh_id += 100;
|
|
+ reply.RetCodeType = RetCodeCheck;
|
|
+ reply.RetCode = EINTR;
|
|
+ err = mach_msg (&reply.Head, MACH_SEND_MSG, sizeof (reply), 0, MACH_PORT_NULL,
|
|
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ /* Receive the retried rpc, and check that it has the same payload
|
|
+ * as the first one. Port names might still be different. */
|
|
+ err = mach_msg (&m2.head, MACH_RCV_MSG, 0, sizeof (m2), rxport,
|
|
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
+ TEST_COMPARE (m1.head.msgh_bits, m2.head.msgh_bits);
|
|
+ TEST_COMPARE (m1.head.msgh_size, m2.head.msgh_size);
|
|
+ TEST_COMPARE (m1.head.msgh_id, m2.head.msgh_id);
|
|
+ TEST_COMPARE_BLOB (m1.data, sizeof (m1.data), m2.data, sizeof (m2.data));
|
|
+
|
|
+ /* And finally make the rpc succeed by sending a valid reply */
|
|
+ err = io_read_reply (m2.head.msgh_remote_port, MACH_MSG_TYPE_MOVE_SEND_ONCE,
|
|
+ KERN_SUCCESS, NULL, 0);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+static int do_test (void)
|
|
+{
|
|
+#if ! XSTATE_HELPERS_SUPPORTED
|
|
+ FAIL_UNSUPPORTED ("Test not supported on this arch.");
|
|
+#endif
|
|
+
|
|
+ /* Setup signal handling; we need to handle the signal in the main
|
|
+ * thread, the other ones will explicitely block SIGUSR1. */
|
|
+ struct sigaction act = { 0 };
|
|
+ act.sa_flags = SA_RESTART;
|
|
+ act.sa_sigaction = &handler;
|
|
+ TEST_COMPARE (sigaction (SIGUSR1, &act, NULL), 0);
|
|
+
|
|
+ mach_port_t fakeio;
|
|
+ int err;
|
|
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &fakeio);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ err = mach_port_insert_right (mach_task_self (), fakeio, fakeio,
|
|
+ MACH_MSG_TYPE_MAKE_SEND);
|
|
+ TEST_COMPARE (err, MACH_MSG_SUCCESS);
|
|
+
|
|
+ pthread_t thsender = xpthread_create (NULL, signal_sender, &fakeio);
|
|
+
|
|
+ char *buf;
|
|
+ mach_msg_type_number_t n;
|
|
+ TEST_COMPARE (io_read (fakeio, &buf, &n, 1, 2), 0);
|
|
+
|
|
+ xpthread_join (thsender);
|
|
+ return EXIT_SUCCESS;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
diff --git a/hurd/test-sig-xstate.c b/hurd/test-sig-xstate.c
|
|
new file mode 100644
|
|
index 0000000000..0a68a44fd7
|
|
--- /dev/null
|
|
+++ b/hurd/test-sig-xstate.c
|
|
@@ -0,0 +1,94 @@
|
|
+/* Test the state save/restore procedures during signal handling.
|
|
+
|
|
+ Copyright (C) 2025 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/>. */
|
|
+
|
|
+
|
|
+#include <assert.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include <mach/message.h>
|
|
+#include <mach/gnumach.h>
|
|
+#include <mach/mach_traps.h>
|
|
+#include <mach-shortcuts.h>
|
|
+#include <mach_init.h>
|
|
+#include <hurd/io.h>
|
|
+#include <hurd/io_reply.h>
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/xthread.h>
|
|
+
|
|
+#include "test-xstate.h"
|
|
+
|
|
+static volatile bool loopflag = true;
|
|
+
|
|
+void handler (int signum, siginfo_t *info, void *context)
|
|
+{
|
|
+ char buf3[XSTATE_BUFFER_SIZE];
|
|
+ memset (buf3, 0x77, XSTATE_BUFFER_SIZE);
|
|
+ SET_XSTATE (buf3);
|
|
+ printf ("signal %d setting a different CPU state\n", signum);
|
|
+ loopflag = false;
|
|
+}
|
|
+
|
|
+/* Helper thread to send a signal to the main thread */
|
|
+void* signal_sender (void *arg)
|
|
+{
|
|
+ sigset_t ss;
|
|
+ assert (! sigemptyset (&ss));
|
|
+ assert (! sigaddset (&ss, SIGUSR1));
|
|
+ assert (! sigprocmask (SIG_BLOCK, &ss, NULL));
|
|
+
|
|
+ TEST_COMPARE (kill (getpid (), SIGUSR1), 0);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int do_test (void)
|
|
+{
|
|
+#if ! XSTATE_HELPERS_SUPPORTED
|
|
+ FAIL_UNSUPPORTED ("Test not supported on this arch.");
|
|
+#endif
|
|
+
|
|
+ struct sigaction act = { 0 };
|
|
+ act.sa_sigaction = &handler;
|
|
+ TEST_COMPARE (sigaction (SIGUSR1, &act, NULL), 0);
|
|
+
|
|
+ pthread_t thsender = xpthread_create (NULL, signal_sender, NULL);
|
|
+
|
|
+ char buf1[XSTATE_BUFFER_SIZE], buf2[XSTATE_BUFFER_SIZE];
|
|
+ memset (buf1, 0x33, XSTATE_BUFFER_SIZE);
|
|
+
|
|
+ SET_XSTATE (buf1);
|
|
+
|
|
+ while (loopflag)
|
|
+ ;
|
|
+
|
|
+ GET_XSTATE (buf2);
|
|
+ TEST_COMPARE_BLOB (buf1, sizeof (buf1), buf2, sizeof (buf2));
|
|
+
|
|
+ xpthread_join (thsender);
|
|
+ return EXIT_SUCCESS;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|
|
diff --git a/hurd/test-xstate.h b/hurd/test-xstate.h
|
|
new file mode 100644
|
|
index 0000000000..a8185dcb07
|
|
--- /dev/null
|
|
+++ b/hurd/test-xstate.h
|
|
@@ -0,0 +1,40 @@
|
|
+/* Helpers to test XSTATE during signal handling
|
|
+
|
|
+ Copyright (C) 2025 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/>. */
|
|
+
|
|
+#ifndef _TEST_XSTATE_H
|
|
+#define _TEST_XSTATE_H
|
|
+
|
|
+#if defined __x86_64__ || defined __i386__
|
|
+#define XSTATE_HELPERS_SUPPORTED 1
|
|
+#define XSTATE_BUFFER_SIZE 16
|
|
+#define SET_XSTATE(b) do { \
|
|
+ asm volatile ("movups (%0),%%xmm0" :: "r" (b)); \
|
|
+ } while (0)
|
|
+
|
|
+#define GET_XSTATE(b) do { \
|
|
+ asm volatile ("movups %%xmm0,(%0)" :: "r" (b)); \
|
|
+ } while (0)
|
|
+
|
|
+#else
|
|
+#define XSTATE_HELPERS_SUPPORTED 0
|
|
+#define XSTATE_BUFFER_SIZE 1
|
|
+#define SET_XSTATE(b)
|
|
+#endif
|
|
+
|
|
+#endif /* _TEST_XSTATE_H */
|
|
diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h
|
|
index 6e5e220e9d..c44e4deac6 100644
|
|
--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
|
|
+++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
|
|
@@ -88,6 +88,8 @@ struct sigcontext
|
|
struct i386_fp_save sc_fpsave;
|
|
struct i386_fp_regs sc_fpregs;
|
|
int sc_fpexcsr; /* FPSR including exception bits. */
|
|
+
|
|
+ struct i386_xfloat_state *xstate;
|
|
};
|
|
|
|
/* Traditional BSD names for some members. */
|
|
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
|
|
index ce8df8d02b..37fa984070 100644
|
|
--- a/sysdeps/mach/hurd/i386/sigreturn.c
|
|
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
|
|
@@ -21,6 +21,8 @@
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
+#include <cpuid.h>
|
|
+
|
|
/* This is run on the thread stack after restoring it, to be able to
|
|
unlock SS off sigstack. */
|
|
static void
|
|
@@ -123,10 +125,32 @@ __sigreturn (struct sigcontext *scp)
|
|
if (scp->sc_onstack)
|
|
ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
|
|
|
|
- if (scp->sc_fpused)
|
|
- /* Restore the FPU state. Mach conveniently stores the state
|
|
- in the format the i387 `frstor' instruction uses to restore it. */
|
|
- asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
|
|
+#ifdef i386_XFLOAT_STATE
|
|
+ if ((scp->xstate) && (scp->xstate->initialized))
|
|
+ {
|
|
+ unsigned eax, ebx, ecx, edx;
|
|
+ __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
+ switch (scp->xstate->fp_save_kind)
|
|
+ {
|
|
+ case 0: // FNSAVE
|
|
+ asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
+ break;
|
|
+ case 1: // FXSAVE
|
|
+ asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
+ asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ if (scp->sc_fpused)
|
|
+ /* Restore the FPU state. Mach conveniently stores the state
|
|
+ in the format the i387 `frstor' instruction uses to restore it. */
|
|
+ asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
|
|
|
|
{
|
|
/* There are convenient instructions to pop state off the stack, so we
|
|
diff --git a/sysdeps/mach/hurd/x86/trampoline.c b/sysdeps/mach/hurd/x86/trampoline.c
|
|
index 8e2890f8c5..db756e8a1f 100644
|
|
--- a/sysdeps/mach/hurd/x86/trampoline.c
|
|
+++ b/sysdeps/mach/hurd/x86/trampoline.c
|
|
@@ -26,7 +26,11 @@
|
|
#include "hurdfault.h"
|
|
#include <intr-msg.h>
|
|
#include <sys/ucontext.h>
|
|
-
|
|
+#ifdef __x86_64__
|
|
+#include <mach/x86_64/mach_i386.h>
|
|
+#else
|
|
+#include <mach/i386/mach_i386.h>
|
|
+#endif
|
|
|
|
/* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers. */
|
|
static void fill_siginfo (siginfo_t *si, int signo,
|
|
@@ -106,6 +110,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
void firewall (void);
|
|
void *sigsp;
|
|
struct sigcontext *scp;
|
|
+ vm_size_t xstate_size;
|
|
struct
|
|
{
|
|
union
|
|
@@ -145,6 +150,14 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
struct hurd_userlink link;
|
|
ucontext_t ucontext;
|
|
siginfo_t siginfo;
|
|
+#ifdef __x86_64__
|
|
+ char _pad2[56];
|
|
+#else
|
|
+ char _pad2[20];
|
|
+#endif
|
|
+ char xstate[];
|
|
+ /* Don't add anything after xstate, as it's dynamically
|
|
+ sized. */
|
|
} *stackframe;
|
|
|
|
#ifdef __x86_64__
|
|
@@ -170,6 +183,17 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
if (! machine_get_basic_state (ss->thread, state))
|
|
return NULL;
|
|
|
|
+ /* Initialize the size of the CPU extended state, to be saved during
|
|
+ * signal handling */
|
|
+#ifdef i386_XFLOAT_STATE
|
|
+ _Static_assert ((sizeof(*stackframe) + sizeof(struct i386_xfloat_state)) % 64 == 0,
|
|
+ "stackframe size must be multiple of 64-byte minus "
|
|
+ "sizeof(struct i386_xfloat_state), please adjust _pad2");
|
|
+
|
|
+ if (__i386_get_xstate_size(__mach_host_self(), &xstate_size))
|
|
+#endif
|
|
+ xstate_size = 0;
|
|
+
|
|
/* Save the original SP in the gratuitous `esp' slot.
|
|
We may need to reset the SP (the `uesp' slot) to avoid clobbering an
|
|
interrupted RPC frame. */
|
|
@@ -196,14 +220,21 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
#endif
|
|
}
|
|
|
|
- /* Push the arguments to call `trampoline' on the stack. */
|
|
- sigsp -= sizeof (*stackframe);
|
|
-#ifdef __x86_64__
|
|
- /* Align SP at 16 bytes. Coupled with the fact that sigreturn_addr is
|
|
- 16-byte aligned within the stackframe struct, this ensures that it ends
|
|
- up on a 16-byte aligned address, as required by the ABI. */
|
|
- sigsp = (void *) ((uintptr_t) sigsp & ~15UL);
|
|
-#endif
|
|
+ /* Push the arguments to call `trampoline' on the stack.
|
|
+ * The extended state might have a variable size depending on the platform,
|
|
+ * so we dynamically allocate it on the stack frame.*/
|
|
+ sigsp -= sizeof (*stackframe) + xstate_size;
|
|
+
|
|
+ /* Align SP at 64 bytes. This is needed for two reasons:
|
|
+ * - sigreturn_addr is 16-byte aligned within the stackframe
|
|
+ * struct, and this ensures that it ends up on a 16-byte aligned
|
|
+ * address, as required by the ABI.
|
|
+ * - the XSAVE state needs to be aligned at 64 bytes (on both i386 and
|
|
+ * x86_64), so we align the stackframe also at 64 bytes and add the
|
|
+ * required padding at the end, see the _pad2 field.
|
|
+ */
|
|
+ sigsp = (void *) ((uintptr_t) sigsp & ~63UL);
|
|
+
|
|
stackframe = sigsp;
|
|
|
|
if (_hurdsig_catch_memory_fault (stackframe))
|
|
@@ -248,14 +279,40 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
memcpy (&scp->sc_i386_thread_state,
|
|
&state->basic, sizeof (state->basic));
|
|
|
|
- /* struct sigcontext is laid out so that starting at sc_fpkind mimics
|
|
- a struct i386_float_state. */
|
|
- _Static_assert (offsetof (struct sigcontext, sc_i386_float_state)
|
|
- % __alignof__ (struct i386_float_state) == 0,
|
|
- "sc_i386_float_state layout mismatch");
|
|
- ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE,
|
|
- &state->fpu, &scp->sc_i386_float_state,
|
|
- sizeof (state->fpu));
|
|
+ scp->xstate = NULL;
|
|
+#ifdef i386_XFLOAT_STATE
|
|
+ if (xstate_size > 0)
|
|
+ {
|
|
+ mach_msg_type_number_t got = (xstate_size / sizeof (int));
|
|
+
|
|
+ ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE,
|
|
+ (thread_state_t) stackframe->xstate, &got)
|
|
+ && got == (xstate_size / sizeof (int)));
|
|
+
|
|
+ if (((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 5)
|
|
+ /* We support up to XSAVES */
|
|
+ ok = 0;
|
|
+
|
|
+ if (ok)
|
|
+ {
|
|
+ scp->xstate = (struct i386_xfloat_state*) stackframe->xstate;
|
|
+ assert((uintptr_t)scp->xstate->hw_state % 64 == 0);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ ok = 0;
|
|
+ if (!ok)
|
|
+ {
|
|
+ /* struct sigcontext is laid out so that starting at sc_fpkind mimics
|
|
+ a struct i386_float_state. */
|
|
+ _Static_assert (offsetof (struct sigcontext, sc_i386_float_state)
|
|
+ % __alignof__ (struct i386_float_state) == 0,
|
|
+ "sc_i386_float_state layout mismatch");
|
|
+ ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE,
|
|
+ &state->fpu, &scp->sc_i386_float_state,
|
|
+ sizeof (state->fpu));
|
|
+ }
|
|
|
|
/* Set up the arguments for the signal handler. */
|
|
stackframe->signo = signo;
|
|
diff --git a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
|
|
index 7bac881176..d83795fcbc 100644
|
|
--- a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
|
|
+++ b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
|
|
@@ -96,6 +96,8 @@ struct sigcontext
|
|
struct i386_fp_save sc_fpsave;
|
|
struct i386_fp_regs sc_fpregs;
|
|
int sc_fpexcsr; /* FPSR including exception bits. */
|
|
+
|
|
+ struct i386_xfloat_state *xstate;
|
|
};
|
|
|
|
/* Traditional BSD names for some members. */
|
|
diff --git a/sysdeps/mach/hurd/x86_64/sigreturn.c b/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
index 81a2d3ba74..dff8e76dc8 100644
|
|
--- a/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
+++ b/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
@@ -20,6 +20,8 @@
|
|
#include <hurd/msg.h>
|
|
#include <stdlib.h>
|
|
|
|
+#include <cpuid.h>
|
|
+
|
|
/* This is run on the thread stack after restoring it, to be able to
|
|
unlock SS off sigstack. */
|
|
void
|
|
@@ -116,10 +118,32 @@ __sigreturn (struct sigcontext *scp)
|
|
if (scp->sc_onstack)
|
|
ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
|
|
|
|
- if (scp->sc_fpused)
|
|
- /* Restore the FPU state. Mach conveniently stores the state
|
|
- in the format the i387 `frstor' instruction uses to restore it. */
|
|
- asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
|
|
+#ifdef i386_XFLOAT_STATE
|
|
+ if ((scp->xstate) && (scp->xstate->initialized))
|
|
+ {
|
|
+ unsigned eax, ebx, ecx, edx;
|
|
+ __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
+ switch (scp->xstate->fp_save_kind)
|
|
+ {
|
|
+ case 0: // FNSAVE
|
|
+ asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
+ break;
|
|
+ case 1: // FXSAVE
|
|
+ asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
+ asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+#endif
|
|
+ if (scp->sc_fpused)
|
|
+ /* Restore the FPU state. Mach conveniently stores the state
|
|
+ in the format the i387 `frstor' instruction uses to restore it. */
|
|
+ asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
|
|
|
|
/* Copy the registers onto the user's stack, to be able to release the
|
|
altstack (by unlocking sigstate). Note that unless an altstack is used,
|
|
--
|
|
2.51.0
|
|
|
|
From 8d54b428cfe98c21049f94c8af3bf302e44091e9 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
|
Date: Mon, 21 Apr 2025 19:42:27 +0200
|
|
Subject: [PATCH] hurd: Do not restore xstate when it is not initialized
|
|
|
|
If the process has never used fp before getting a signal, xstate is set
|
|
(and thus the x87 state is not initialized) but xstate->initialized is still
|
|
0, and we should not restore anything.
|
|
---
|
|
sysdeps/mach/hurd/i386/sigreturn.c | 37 +++++++++++++++-------------
|
|
sysdeps/mach/hurd/x86_64/sigreturn.c | 37 +++++++++++++++-------------
|
|
2 files changed, 40 insertions(+), 34 deletions(-)
|
|
|
|
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
|
|
index 37fa984070..dc57d6122c 100644
|
|
--- a/sysdeps/mach/hurd/i386/sigreturn.c
|
|
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
|
|
@@ -126,24 +126,27 @@ __sigreturn (struct sigcontext *scp)
|
|
ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
|
|
|
|
#ifdef i386_XFLOAT_STATE
|
|
- if ((scp->xstate) && (scp->xstate->initialized))
|
|
+ if (scp->xstate)
|
|
{
|
|
- unsigned eax, ebx, ecx, edx;
|
|
- __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
- switch (scp->xstate->fp_save_kind)
|
|
- {
|
|
- case 0: // FNSAVE
|
|
- asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
- break;
|
|
- case 1: // FXSAVE
|
|
- asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
- "a" (eax), "d" (edx));
|
|
- break;
|
|
- default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
- asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
- "a" (eax), "d" (edx));
|
|
- break;
|
|
- }
|
|
+ if (scp->xstate->initialized)
|
|
+ {
|
|
+ unsigned eax, ebx, ecx, edx;
|
|
+ __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
+ switch (scp->xstate->fp_save_kind)
|
|
+ {
|
|
+ case 0: // FNSAVE
|
|
+ asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
+ break;
|
|
+ case 1: // FXSAVE
|
|
+ asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
+ asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
else
|
|
#endif
|
|
diff --git a/sysdeps/mach/hurd/x86_64/sigreturn.c b/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
index dff8e76dc8..773c00f86d 100644
|
|
--- a/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
+++ b/sysdeps/mach/hurd/x86_64/sigreturn.c
|
|
@@ -119,24 +119,27 @@ __sigreturn (struct sigcontext *scp)
|
|
ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
|
|
|
|
#ifdef i386_XFLOAT_STATE
|
|
- if ((scp->xstate) && (scp->xstate->initialized))
|
|
+ if (scp->xstate)
|
|
{
|
|
- unsigned eax, ebx, ecx, edx;
|
|
- __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
- switch (scp->xstate->fp_save_kind)
|
|
- {
|
|
- case 0: // FNSAVE
|
|
- asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
- break;
|
|
- case 1: // FXSAVE
|
|
- asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
- "a" (eax), "d" (edx));
|
|
- break;
|
|
- default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
- asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
- "a" (eax), "d" (edx));
|
|
- break;
|
|
- }
|
|
+ if (scp->xstate->initialized)
|
|
+ {
|
|
+ unsigned eax, ebx, ecx, edx;
|
|
+ __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
|
|
+ switch (scp->xstate->fp_save_kind)
|
|
+ {
|
|
+ case 0: // FNSAVE
|
|
+ asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
|
|
+ break;
|
|
+ case 1: // FXSAVE
|
|
+ asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
|
|
+ asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state), \
|
|
+ "a" (eax), "d" (edx));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
else
|
|
#endif
|
|
--
|
|
2.51.0
|
|
|
|
From 0f2df19d9535d234b31c65f84a6c67ac2e0bd027 Mon Sep 17 00:00:00 2001
|
|
From: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
|
Date: Mon, 21 Apr 2025 19:45:02 +0200
|
|
Subject: [PATCH] hurd: Do not check for xstate level if it was not
|
|
initialized
|
|
|
|
If __thread_get_state failed, there is no xstate level to check.
|
|
ok is 0 already and the memory exists, but better not read uninitialized
|
|
memory.
|
|
---
|
|
sysdeps/mach/hurd/x86/trampoline.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sysdeps/mach/hurd/x86/trampoline.c b/sysdeps/mach/hurd/x86/trampoline.c
|
|
index db756e8a1f..02510b178c 100644
|
|
--- a/sysdeps/mach/hurd/x86/trampoline.c
|
|
+++ b/sysdeps/mach/hurd/x86/trampoline.c
|
|
@@ -289,7 +289,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action
|
|
(thread_state_t) stackframe->xstate, &got)
|
|
&& got == (xstate_size / sizeof (int)));
|
|
|
|
- if (((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 5)
|
|
+ if (ok && ((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 5)
|
|
/* We support up to XSAVES */
|
|
ok = 0;
|
|
|
|
--
|
|
2.51.0
|
|
|