linux-um.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: David Gow <davidgow@google.com>
To: Benjamin Berg <benjamin@sipsolutions.net>
Cc: kunit-dev@googlegroups.com, linux-um@lists.infradead.org,
	"Thomas Weißschuh" <thomas.weissschuh@linutronix.de>,
	"Benjamin Berg" <benjamin.berg@intel.com>
Subject: Re: [RFC 2/2] um: add a mcontext FP register handling test
Date: Wed, 2 Jul 2025 14:04:44 +0800	[thread overview]
Message-ID: <CABVgOSmVtZvO1_kZgac=fsisMRmrAsv6-ZTcb4RS8d6Q+rbjxw@mail.gmail.com> (raw)
In-Reply-To: <20250626195714.2123694-3-benjamin@sipsolutions.net>

[-- Attachment #1: Type: text/plain, Size: 7913 bytes --]

On Fri, 27 Jun 2025 at 03:59, Benjamin Berg <benjamin@sipsolutions.net> wrote:
>
> From: Benjamin Berg <benjamin.berg@intel.com>
>
> This tests checks whether floating point registers are properly saved
> into the signal context and restored again. The test works by having a
> known value at the top of the FP register stack and in the first xmm
> register. Then SIGUSR1 is triggered and both of these registers are
> modified by changing the values in the mcontext.
>
> Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
> ---

I really like this as an example of what we can do with UAPI tests.

Alongside the comments from Thomas, one small note below that we'd
need to put any SSE stuff behind a check for SSE support (at least on
32-bit), and skip the test.

Cheers,
-- David

>  arch/x86/um/Makefile                     |   2 +
>  arch/x86/um/tests/Makefile               |  12 +++
>  arch/x86/um/tests/registers.c            |  22 +++++
>  arch/x86/um/tests/test-fp-save-restore.c | 118 +++++++++++++++++++++++
>  4 files changed, 154 insertions(+)
>  create mode 100644 arch/x86/um/tests/Makefile
>  create mode 100644 arch/x86/um/tests/registers.c
>  create mode 100644 arch/x86/um/tests/test-fp-save-restore.c
>
> diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
> index b42c31cd2390..410f5526f1f4 100644
> --- a/arch/x86/um/Makefile
> +++ b/arch/x86/um/Makefile
> @@ -15,6 +15,8 @@ obj-y = bugs_$(BITS).o delay.o fault.o \
>         sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
>         mem_$(BITS).o subarch.o os-Linux/
>
> +obj-y += tests/
> +
>  ifeq ($(CONFIG_X86_32),y)
>
>  obj-y += syscalls_32.o
> diff --git a/arch/x86/um/tests/Makefile b/arch/x86/um/tests/Makefile
> new file mode 100644
> index 000000000000..c3a868b078f3
> --- /dev/null
> +++ b/arch/x86/um/tests/Makefile
> @@ -0,0 +1,12 @@
> +include $(srctree)/init/Makefile.nolibc
> +
> +ccflags-y := -I$(obj)
> +
> +um-tests-y += registers.o
> +
> +userprogs += test-fp-save-restore
> +test-fp-save-restore-userccflags := -static $(NOLIBC_USERCFLAGS) -msse
> +
> +obj-$(CONFIG_KUNIT_UAPI) += um-tests.o
> +
> +$(obj)/registers.o: $(obj)/test-fp-save-restore
> diff --git a/arch/x86/um/tests/registers.c b/arch/x86/um/tests/registers.c
> new file mode 100644
> index 000000000000..2c4e55da043c
> --- /dev/null
> +++ b/arch/x86/um/tests/registers.c
> @@ -0,0 +1,22 @@
> +#include <kunit/test.h>
> +#include <kunit/test-bug.h>
> +#include <kunit/uapi.h>
> +
> +static void test_mcontext(struct kunit *test)
> +{
> +       KUNIT_UAPI_EMBED_BLOB(test_fp_save_restore, "test-fp-save-restore");
> +
> +       kunit_uapi_run_kselftest(test, &test_fp_save_restore);
> +}
> +
> +static struct kunit_case register_test_cases[] = {
> +       KUNIT_CASE(test_mcontext),
> +       {}
> +};
> +
> +static struct kunit_suite register_test_suite = {
> +       .name = "um_registers",
> +       .test_cases = register_test_cases,
> +};
> +
> +kunit_test_suites(&register_test_suite);
> diff --git a/arch/x86/um/tests/test-fp-save-restore.c b/arch/x86/um/tests/test-fp-save-restore.c
> new file mode 100644
> index 000000000000..28a32ca374fe
> --- /dev/null
> +++ b/arch/x86/um/tests/test-fp-save-restore.c
> @@ -0,0 +1,118 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Test FP register handling in userspace mcontext.
> + *
> + * Copyright (C) 2025 Intel Corporation
> + */
> +
> +#include <math.h>
> +#include <signal.h>
> +#include <types.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys.h>
> +#include <asm/sigcontext.h>
> +#include <asm/ucontext.h>
> +
> +#include "../../../tools/testing/selftests/kselftest.h"
> +
> +#define ST0_EXP_ADD 10
> +
> +static void sighandler(int sig, siginfo_t *info, void *p)
> +{
> +       struct ucontext *uc = p;
> +       struct _fpstate *fpstate = (void *)uc->uc_mcontext.fpstate;
> +
> +       ksft_print_msg("sighandler: extended_size: %d, xstate_size: %d\n",
> +                      fpstate->sw_reserved.extended_size,
> +                      fpstate->sw_reserved.xstate_size);
> +
> +#ifdef __i386__
> +       fpstate->_st[0].exponent += ST0_EXP_ADD;
> +       fpstate->_xmm[1].element[0] |= 0x01010101;
> +       fpstate->_xmm[1].element[1] |= 0x01010101;
> +       fpstate->_xmm[1].element[2] |= 0x01010101;
> +       fpstate->_xmm[1].element[3] |= 0x01010101;
> +#else
> +       /* Hacky way of modifying the exponent without breaking aliasing */
> +       fpstate->st_space[2] += ST0_EXP_ADD;
> +       fpstate->xmm_space[4] |= 0x01010101;
> +       fpstate->xmm_space[5] |= 0x01010101;
> +       fpstate->xmm_space[6] |= 0x01010101;
> +       fpstate->xmm_space[7] |= 0x01010101;
> +#endif
> +}
> +
> +static int test_mcontext(int xmm_should_change)
> +{
> +       double num = 0.5;
> +       uint32_t sse[4] = {0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00 };
> +       long ret;
> +       int xmm_manipulated;
> +
> +       ksft_print_msg("pre-signal:  %d / 100, %08x %08x %08x %08x\n", (int) (100*num), sse[0], sse[1], sse[2], sse[3]);
> +       /*
> +        * This does kill(getpid(), SIGUSR1); with "num" being passed in AND
> +        * out of the floating point stack. We can therefore modify num by
> +        * changing st[0] when handling the signal.
> +        */
> +#ifdef __i386__

Just to ruin your day, the SSE register stuff probably needs to be
behind some check for SSE support.

> +       asm volatile (
> +               "movups %1, %%xmm1;"
> +               "int $0x80;"
> +               "movups %%xmm1, %1;"
> +               : "=t" (num), "=m" (sse), "=a" (ret)
> +               : "0" (num), "2" (__NR_kill), "b" (getpid()), "c" (SIGUSR1) :
> +               "xmm1", "memory");
> +#else
> +       asm volatile (
> +               "movups %1, %%xmm1;"
> +               "syscall;"
> +               "movups %%xmm1, %1;"
> +               : "=t" (num), "=m"(sse), "=a" (ret)
> +               : "0" (num), "2" (__NR_kill), "D" (getpid()), "S" (SIGUSR1)
> +               : "r11", "rcx", "xmm1", "memory");
> +#endif
> +       if (sse[0] == 0x11223344 || sse[1] == 0x55667788 || sse[2] == 0x99aabbcc || sse[3] == 0xddeeff00)
> +               xmm_manipulated = 0;
> +       else if (sse[0] == 0x11233345 || sse[1] == 0x55677789 || sse[2] == 0x99abbbcd || sse[3] == 0xddefff01)
> +               xmm_manipulated = 1;
> +       else
> +               xmm_manipulated = 2;
> +
> +       ksft_print_msg("post-signal: %d / 100, %08x %08x %08x %08x (should change: %d, changed: %d)\n",
> +                      (int) (100 * num), sse[0], sse[1], sse[2], sse[3], xmm_should_change, xmm_manipulated);
> +
> +       if (num != (1 << (ST0_EXP_ADD - 1))) {
> +               ksft_print_msg("floating point register was not manipulated\n");
> +               return 1;
> +       }
> +
> +       if (xmm_manipulated != xmm_should_change) {
> +               ksft_print_msg("xmm/sse had unexpected value!\n");
> +               return 1;
> +       }
> +
> +       return 0;
> +}
> +
> +int main(void)
> +{
> +       struct sigaction sa = {
> +               .sa_flags = SA_SIGINFO,
> +               .sa_handler = (void (*)(int))sighandler,
> +       };
> +
> +       ksft_print_header();
> +       ksft_set_plan(1);
> +
> +       if (sys_sigaction(SIGUSR1, &sa, NULL) < 0)
> +               ksft_exit_fail_msg("Failed to register sigaction: %d\n", errno);
> +
> +       if (!test_mcontext(1))
> +               ksft_test_result_pass("mcontext\n");
> +       else
> +               ksft_test_result_fail("mcontext failed!\n");
> +
> +       ksft_finished();
> +}
> --
> 2.50.0
>
> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/kunit-dev/20250626195714.2123694-3-benjamin%40sipsolutions.net.

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5281 bytes --]

  parent reply	other threads:[~2025-07-02  6:07 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-26 19:57 [RFC 0/2] Experimental kunit test for signal context handling Benjamin Berg
2025-06-26 19:57 ` [RFC 1/2] tools/nolibc: add sigaction() Benjamin Berg
2025-06-27  4:48   ` Thomas Weißschuh
2025-06-27  6:46     ` Berg, Benjamin
2025-06-27  7:45       ` Thomas Weißschuh
2025-06-27  8:14         ` Berg, Benjamin
2025-06-26 19:57 ` [RFC 2/2] um: add a mcontext FP register handling test Benjamin Berg
2025-06-27  5:01   ` Thomas Weißschuh
2025-07-02  6:04   ` David Gow [this message]
2025-06-27  4:33 ` [RFC 0/2] Experimental kunit test for signal context handling Thomas Weißschuh
2025-06-27  7:29   ` Benjamin Berg
2025-06-27  8:43     ` Thomas Weißschuh
2025-06-27  8:48       ` Benjamin Berg
2025-06-27  9:22         ` Thomas Weißschuh
2025-06-27  9:28           ` Benjamin Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABVgOSmVtZvO1_kZgac=fsisMRmrAsv6-ZTcb4RS8d6Q+rbjxw@mail.gmail.com' \
    --to=davidgow@google.com \
    --cc=benjamin.berg@intel.com \
    --cc=benjamin@sipsolutions.net \
    --cc=kunit-dev@googlegroups.com \
    --cc=linux-um@lists.infradead.org \
    --cc=thomas.weissschuh@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).