[RFC 0/2] Experimental kunit test for signal context handling

3 views
Skip to first unread message

Benjamin Berg

unread,
Jun 26, 2025, 3:59:18 PM6/26/25
to kuni...@googlegroups.com, linu...@lists.infradead.org, Thomas Weißschuh, Benjamin Berg
From: Benjamin Berg <benjam...@intel.com>

Hi,

so I saw the UAPI testing framework patches and wondered whether I could
hack up a kunit test for userspace signal mcontext handling. I already
had some code, but never knew where to include it. Having it as a kunit
test in this way seems nice as it makes running the test really simple.

This is a very rough attempt with an extra patch to add sigaction
support as that is needed by the test.

Note that this type of test could possibly be shared with the x86
architecture (though UM does not support all features). And, a 64 bit
build might even want to include a second 32 bit binary. So, I suppose
one would ideally want the test to be in arch/x86/tests, with some way
to pick up it up in arch/x86/um/tests.

Does this seem sensible in general?

Benjamin

Benjamin Berg (2):
tools/nolibc: add sigaction()
um: add a mcontext FP register handling test

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 +++++++++++++++++++++++
tools/include/nolibc/nolibc.h | 3 +
tools/include/nolibc/signal.h | 34 +++++++
6 files changed, 191 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

--
2.50.0

Benjamin Berg

unread,
Jun 26, 2025, 3:59:19 PM6/26/25
to kuni...@googlegroups.com, linu...@lists.infradead.org, Thomas Weißschuh, Benjamin Berg
From: Benjamin Berg <benjam...@intel.com>

In preparation to add tests that use it.

Signed-off-by: Benjamin Berg <benjam...@intel.com>
---
tools/include/nolibc/nolibc.h | 3 +++
tools/include/nolibc/signal.h | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)

diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index c199ade200c2..29e37a755aba 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -92,6 +92,9 @@
#ifndef _NOLIBC_H
#define _NOLIBC_H

+/* So that we do not get compatibility types/defines */
+#define __KERNEL__
+
#include "std.h"
#include "arch.h"
#include "types.h"
diff --git a/tools/include/nolibc/signal.h b/tools/include/nolibc/signal.h
index ac13e53ac31d..fa52119e577f 100644
--- a/tools/include/nolibc/signal.h
+++ b/tools/include/nolibc/signal.h
@@ -14,6 +14,7 @@
#include "arch.h"
#include "types.h"
#include "sys.h"
+#include <linux/signal.h>

/* This one is not marked static as it's needed by libgcc for divide by zero */
int raise(int signal);
@@ -23,4 +24,37 @@ int raise(int signal)
return sys_kill(sys_getpid(), signal);
}

+/*
+ * sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+ */
+
+#ifdef SA_RESTORER
+__attribute__((naked))
+static void my_sa_restorer(void)
+{
+ my_syscall0(__NR_rt_sigreturn);
+}
+#endif
+
+static __attribute__((unused))
+int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+ struct sigaction real_act = *act;
+#ifdef SA_RESTORER
+ if (!(real_act.sa_flags & SA_RESTORER)) {
+ real_act.sa_flags |= SA_RESTORER;
+ real_act.sa_restorer = my_sa_restorer;
+ }
+#endif
+
+ return my_syscall4(__NR_rt_sigaction, signum, &real_act, oldact,
+ sizeof(act->sa_mask));
+}
+
+static __attribute__((unused))
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+ return __sysret(sys_sigaction(signum, act, oldact));
+}
+
#endif /* _NOLIBC_SIGNAL_H */
--
2.50.0

Benjamin Berg

unread,
Jun 26, 2025, 3:59:21 PM6/26/25
to kuni...@googlegroups.com, linu...@lists.infradead.org, Thomas Weißschuh, Benjamin Berg
From: Benjamin Berg <benjam...@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 <benjam...@intel.com>
---
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__
+ 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

Thomas Weißschuh

unread,
Jun 27, 2025, 12:33:42 AM6/27/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org, Benjamin Berg
Hi,

On Thu, Jun 26, 2025 at 09:57:12PM +0200, Benjamin Berg wrote:
> so I saw the UAPI testing framework patches and wondered whether I could
> hack up a kunit test for userspace signal mcontext handling. I already
> had some code, but never knew where to include it. Having it as a kunit
> test in this way seems nice as it makes running the test really simple.

Nice to hear that you find it useful.

> This is a very rough attempt with an extra patch to add sigaction
> support as that is needed by the test.
>
> Note that this type of test could possibly be shared with the x86
> architecture (though UM does not support all features).

Can the expected feature detection be performed at runtime?
If so I would write the test as x86 kselftest in tools/testing/kselftests/x86/
and then also hook it up for kunit on UML and x86.
This gives you the advantages of all worlds.

For an example see [0]. That is still based on an old version of the framework,
so can't be used as-is. But you should get the idea.

> And, a 64 bit build might even want to include a second 32 bit binary.

Indeed, for compat binaries we'll probably want some sort of common pattern.
Unfortunately it's not as easy as building a second binary when CONFIG_COMPAT=y,
as some architectures have more than 2 supported ABIs. MIPS for example or x86_64
when counting x32.
Or maybe we can just pretend that those don't matter.
Something we can work on when the first series has been merged.

> So, I suppose
> one would ideally want the test to be in arch/x86/tests, with some way
> to pick up it up in arch/x86/um/tests.
>
> Does this seem sensible in general?

It does.

> Benjamin

[0] https://git.kernel.org/pub/scm/linux/kernel/git/thomas.weissschuh/linux.git/commit/?h=kunit-kselftests-integration&id=14bf93f09eaa328a18e9190f46fa4ee697378617

Thomas Weißschuh

unread,
Jun 27, 2025, 12:48:57 AM6/27/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org, Benjamin Berg
On Thu, Jun 26, 2025 at 09:57:13PM +0200, Benjamin Berg wrote:
> From: Benjamin Berg <benjam...@intel.com>
>
> In preparation to add tests that use it.

I tried to implement signal support in nolibc before but ran into some issues.
Unfortunately I don't remember the details.
But I guess you know more about signals than me, so let's try it again.
In any case this should add some tests to
tools/testing/selftests/nolibc/nolibc-test.c.

If you test it with qemu-user please be aware that there were issues around
SA_RESTORER up until recently [0] [1].

[1] https://lore.kernel.org/qemu-devel/20250202-riscv-sa-rest...@t-8ch.de/
[0] https://lore.kernel.org/qemu-devel/mvmed06...@suse.de/

>
> Signed-off-by: Benjamin Berg <benjam...@intel.com>
> ---
> tools/include/nolibc/nolibc.h | 3 +++
> tools/include/nolibc/signal.h | 34 ++++++++++++++++++++++++++++++++++
> 2 files changed, 37 insertions(+)
>
> diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
> index c199ade200c2..29e37a755aba 100644
> --- a/tools/include/nolibc/nolibc.h
> +++ b/tools/include/nolibc/nolibc.h
> @@ -92,6 +92,9 @@
> #ifndef _NOLIBC_H
> #define _NOLIBC_H
>
> +/* So that we do not get compatibility types/defines */
> +#define __KERNEL__

Could you explain this more?

The user may have included kernel UAPI headers already before including nolibc,
so it doesn't really work.

> +
> #include "std.h"
> #include "arch.h"
> #include "types.h"
> diff --git a/tools/include/nolibc/signal.h b/tools/include/nolibc/signal.h
> index ac13e53ac31d..fa52119e577f 100644
> --- a/tools/include/nolibc/signal.h
> +++ b/tools/include/nolibc/signal.h
> @@ -14,6 +14,7 @@
> #include "arch.h"
> #include "types.h"
> #include "sys.h"
> +#include <linux/signal.h>
>
> /* This one is not marked static as it's needed by libgcc for divide by zero */
> int raise(int signal);
> @@ -23,4 +24,37 @@ int raise(int signal)
> return sys_kill(sys_getpid(), signal);
> }
>
> +/*
> + * sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
> + */
> +
> +#ifdef SA_RESTORER
> +__attribute__((naked))

__attribute__((naked)) is not supported everywhere.

> +static void my_sa_restorer(void)

This should use a name with less potential to conflict with user code.
Like __nolibc_sa_restorer().

> +{
> + my_syscall0(__NR_rt_sigreturn);
> +}
> +#endif
> +
> +static __attribute__((unused))
> +int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
> +{
> + struct sigaction real_act = *act;
> +#ifdef SA_RESTORER
> + if (!(real_act.sa_flags & SA_RESTORER)) {
> + real_act.sa_flags |= SA_RESTORER;
> + real_act.sa_restorer = my_sa_restorer;
> + }
> +#endif
> +
> + return my_syscall4(__NR_rt_sigaction, signum, &real_act, oldact,
> + sizeof(act->sa_mask));

No need for the linebreak.

Thomas Weißschuh

unread,
Jun 27, 2025, 1:01:17 AM6/27/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org, Benjamin Berg
As mentiond before, I'd like to find out why you need this.

> +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

Create a dedicated Kconfig option for this.
Not everybody who has enabled the framework wants to include these testcases.
Also the tests can stay in a module even if CONFIG_KUNIT_UAPI=y.

> +
> +$(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>

Unnecessary.

> +#include <kunit/uapi.h>
> +
> +static void test_mcontext(struct kunit *test)
> +{
> + KUNIT_UAPI_EMBED_BLOB(test_fp_save_restore, "test-fp-save-restore");

Any reason to have different names between the userprog and the testcase?
Keeping them consistent will make it easier for the user.
types.h is specific to nolibc. Can probably just be dropped.

> +#include <unistd.h>
> +#include <string.h>
> +#include <sys.h>

sys.h is specific to nolibc. Use a standard header instead.

> +#include <asm/sigcontext.h>
> +#include <asm/ucontext.h>
> +
> +#include "../../../tools/testing/selftests/kselftest.h"

I can't say anything about the actual tests.

<snip>

Berg, Benjamin

unread,
Jun 27, 2025, 2:47:17 AM6/27/25
to thomas.w...@linutronix.de, kuni...@googlegroups.com, linu...@lists.infradead.org
On Fri, 2025-06-27 at 06:48 +0200, Thomas Weißschuh wrote:
> On Thu, Jun 26, 2025 at 09:57:13PM +0200, Benjamin Berg wrote:
> > From: Benjamin Berg <benjam...@intel.com>
> >
> > In preparation to add tests that use it.
>
> I tried to implement signal support in nolibc before but ran into some issues.
> Unfortunately I don't remember the details.
> But I guess you know more about signals than me, so let's try it again.
> In any case this should add some tests to
> tools/testing/selftests/nolibc/nolibc-test.c.
>
> If you test it with qemu-user please be aware that there were issues around
> SA_RESTORER up until recently [0] [1].

Oh, is there a convenient way to cross-compile for various
architectures and run them using qemu?

So far I only tried x86/x86_64.

>
> [1] https://lore.kernel.org/qemu-devel/20250202-riscv-sa-rest...@t-8ch.de/
> [0] https://lore.kernel.org/qemu-devel/mvmed06...@suse.de/
>
> >
> > Signed-off-by: Benjamin Berg <benjam...@intel.com>
> > ---
> >  tools/include/nolibc/nolibc.h |  3 +++
> >  tools/include/nolibc/signal.h | 34 ++++++++++++++++++++++++++++++++++
> >  2 files changed, 37 insertions(+)
> >
> > diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
> > index c199ade200c2..29e37a755aba 100644
> > --- a/tools/include/nolibc/nolibc.h
> > +++ b/tools/include/nolibc/nolibc.h
> > @@ -92,6 +92,9 @@
> >  #ifndef _NOLIBC_H
> >  #define _NOLIBC_H
> >  
> > +/* So that we do not get compatibility types/defines */
> > +#define __KERNEL__
>
> Could you explain this more?
>
> The user may have included kernel UAPI headers already before including nolibc,
> so it doesn't really work.

Maybe we should just set it in the CFLAGS directly then?

Honestly, I am not entirely sure how you are supposed to do it
correctly. The thing is, if I do not set __KERNEL__, then I get the old
compatibility defines and types from asm/signal.h.

And, I do not see an alternative way. It would not be safe to avoid the
include entirely and if you try that you are also missing the
SA_RESTORER define for the proper "struct sigaction" definition to be
correct.

The best alternative I see would be copying the proper definitions into
the architecture specific header. That would also be ugly, as one would
need to do a "struct sigaction" -> "struct nolibc_rt_sigaction"
conversion internally. But, that would have the advantage that nolibc
works outside of the kernel tree.

Even if all this is ugly, I would prefer that over using the
compatibility sigaction syscall instead of rt_sigaction.

> > +
> >  #include "std.h"
> >  #include "arch.h"
> >  #include "types.h"
> > diff --git a/tools/include/nolibc/signal.h b/tools/include/nolibc/signal.h
> > index ac13e53ac31d..fa52119e577f 100644
> > --- a/tools/include/nolibc/signal.h
> > +++ b/tools/include/nolibc/signal.h
> > @@ -14,6 +14,7 @@
> >  #include "arch.h"
> >  #include "types.h"
> >  #include "sys.h"
> > +#include <linux/signal.h>
> >  
> >  /* This one is not marked static as it's needed by libgcc for divide by zero */
> >  int raise(int signal);
> > @@ -23,4 +24,37 @@ int raise(int signal)
> >   return sys_kill(sys_getpid(), signal);
> >  }
> >  
> > +/*
> > + * sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
> > + */
> > +
> > +#ifdef SA_RESTORER
> > +__attribute__((naked))
>
> __attribute__((naked)) is not supported everywhere.

One can just drop it. It just felt it was cleaner as we really just
want to set the register and do the syscall without modifying the
stack.

> > +static void my_sa_restorer(void)
>
> This should use a name with less potential to conflict with user code.
> Like __nolibc_sa_restorer().

Sure!

Benjamin
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

Benjamin Berg

unread,
Jun 27, 2025, 3:29:33 AM6/27/25
to Thomas Weißschuh, kuni...@googlegroups.com, linu...@lists.infradead.org
Hi,

On Fri, 2025-06-27 at 06:33 +0200, Thomas Weißschuh wrote:
> Hi,
>
> On Thu, Jun 26, 2025 at 09:57:12PM +0200, Benjamin Berg wrote:
> > so I saw the UAPI testing framework patches and wondered whether I could
> > hack up a kunit test for userspace signal mcontext handling. I already
> > had some code, but never knew where to include it. Having it as a kunit
> > test in this way seems nice as it makes running the test really simple.
>
> Nice to hear that you find it useful.
>
> > This is a very rough attempt with an extra patch to add sigaction
> > support as that is needed by the test.
> >
> > Note that this type of test could possibly be shared with the x86
> > architecture (though UM does not support all features).
>
> Can the expected feature detection be performed at runtime?
> If so I would write the test as x86 kselftest in tools/testing/kselftests/x86/
> and then also hook it up for kunit on UML and x86.
> This gives you the advantages of all worlds.
>
> For an example see [0]. That is still based on an old version of the framework,
> so can't be used as-is. But you should get the idea.

That looks nice, and you do support both x86 and um there!

Many of those checks should be simple as syscalls will return an error
(modify_ldt should return -ENOSYS for example). For more arcane things
one could e.g. add "(um)" into AT_PLATFORM or just disable the kunit
test for the um architecture.

This is a nice development, I absolutely expect to find some bugs in um
this way.

> > And, a 64 bit build might even want to include a second 32 bit binary.
>
> Indeed, for compat binaries we'll probably want some sort of common pattern.
> Unfortunately it's not as easy as building a second binary when CONFIG_COMPAT=y,
> as some architectures have more than 2 supported ABIs. MIPS for example or x86_64
> when counting x32.
> Or maybe we can just pretend that those don't matter.
> Something we can work on when the first series has been merged.

Yes, lets ignore that for now :-)

> > So, I suppose
> > one would ideally want the test to be in arch/x86/tests, with some way
> > to pick up it up in arch/x86/um/tests.
> >
> > Does this seem sensible in general?
>
> It does.

Nice!

Benjamin

Thomas Weißschuh

unread,
Jun 27, 2025, 3:45:26 AM6/27/25
to Berg, Benjamin, kuni...@googlegroups.com, linu...@lists.infradead.org
On Fri, Jun 27, 2025 at 06:46:56AM +0000, Berg, Benjamin wrote:
> On Fri, 2025-06-27 at 06:48 +0200, Thomas Weißschuh wrote:
> > On Thu, Jun 26, 2025 at 09:57:13PM +0200, Benjamin Berg wrote:
> > > From: Benjamin Berg <benjam...@intel.com>
> > >
> > > In preparation to add tests that use it.
> >
> > I tried to implement signal support in nolibc before but ran into some issues.
> > Unfortunately I don't remember the details.
> > But I guess you know more about signals than me, so let's try it again.
> > In any case this should add some tests to
> > tools/testing/selftests/nolibc/nolibc-test.c.
> >
> > If you test it with qemu-user please be aware that there were issues around
> > SA_RESTORER up until recently [0] [1].
>
> Oh, is there a convenient way to cross-compile for various
> architectures and run them using qemu?
>
> So far I only tried x86/x86_64.

We have a script for that in the nolibc testsuite:

$ cd tools/testing/selftests/nolibc/
$ ./run-tests.sh -p -m user
i386: 225 test(s): 222 passed, 3 skipped, 0 failed => status: warning
x86_64: 225 test(s): 222 passed, 3 skipped, 0 failed => status: warning
arm64: 225 test(s): 222 passed, 3 skipped, 0 failed => status: warning
...

"-p" downloads a bunch of toolchains from kernel.org
"-m user" uses qemu-user. "-m system", or no "-m" at all would build a kernel and use qemu-system.
"-l" will use llvm/clang instead of gcc (only use with "-m user").

Actual tests are in nolibc-test.c.

> >
> > [1] https://lore.kernel.org/qemu-devel/20250202-riscv-sa-rest...@t-8ch.de/
> > [0] https://lore.kernel.org/qemu-devel/mvmed06...@suse.de/
> >
> > >
> > > Signed-off-by: Benjamin Berg <benjam...@intel.com>
> > > ---
> > >  tools/include/nolibc/nolibc.h |  3 +++
> > >  tools/include/nolibc/signal.h | 34 ++++++++++++++++++++++++++++++++++
> > >  2 files changed, 37 insertions(+)
> > >
> > > diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
> > > index c199ade200c2..29e37a755aba 100644
> > > --- a/tools/include/nolibc/nolibc.h
> > > +++ b/tools/include/nolibc/nolibc.h
> > > @@ -92,6 +92,9 @@
> > >  #ifndef _NOLIBC_H
> > >  #define _NOLIBC_H
> > >  
> > > +/* So that we do not get compatibility types/defines */
> > > +#define __KERNEL__
> >
> > Could you explain this more?
> >
> > The user may have included kernel UAPI headers already before including nolibc,
> > so it doesn't really work.
>
> Maybe we should just set it in the CFLAGS directly then?

We also don't control the CFLAGS the user is using.

> Honestly, I am not entirely sure how you are supposed to do it
> correctly. The thing is, if I do not set __KERNEL__, then I get the old
> compatibility defines and types from asm/signal.h.
>
> And, I do not see an alternative way. It would not be safe to avoid the
> include entirely and if you try that you are also missing the
> SA_RESTORER define for the proper "struct sigaction" definition to be
> correct.
>
> The best alternative I see would be copying the proper definitions into
> the architecture specific header. That would also be ugly, as one would
> need to do a "struct sigaction" -> "struct nolibc_rt_sigaction"
> conversion internally. But, that would have the advantage that nolibc
> works outside of the kernel tree.

I think we need to do something like this.
Luckily the real mess seems to be only on x86.

> Even if all this is ugly, I would prefer that over using the
> compatibility sigaction syscall instead of rt_sigaction.

As an alternative, you are not forced to use nolibc for the KUnit UAPI
framework. You can depend on CONFIG_CC_CAN_LINK_STATIC=y and use "-static" for
the toolchains "real" libc.
Not that I want to discourage you from contributing to nolibc, though.
If it works without, also good.
If you want you can also use __nolibc_has_attribute(naked) from compiler.h.

<snip>

Berg, Benjamin

unread,
Jun 27, 2025, 4:14:46 AM6/27/25
to thomas.w...@linutronix.de, kuni...@googlegroups.com, linu...@lists.infradead.org
Hi,

On Fri, 2025-06-27 at 09:45 +0200, Thomas Weißschuh wrote:
> On Fri, Jun 27, 2025 at 06:46:56AM +0000, Berg, Benjamin wrote:
> > [SNIP]
> >
> > Oh, is there a convenient way to cross-compile for various
> > architectures and run them using qemu?
> >
> > So far I only tried x86/x86_64.
>
> We have a script for that in the nolibc testsuite:
>
> $ cd tools/testing/selftests/nolibc/
> $ ./run-tests.sh -p -m user
> i386:          225 test(s): 222 passed,   3 skipped,   0 failed => status: warning
> x86_64:        225 test(s): 222 passed,   3 skipped,   0 failed => status: warning
> arm64:         225 test(s): 222 passed,   3 skipped,   0 failed => status: warning
> ...
>
> "-p" downloads a bunch of toolchains from kernel.org
> "-m user" uses qemu-user. "-m system", or no "-m" at all would build a kernel and use qemu-system.
> "-l" will use llvm/clang instead of gcc (only use with "-m user").
>
> Actual tests are in nolibc-test.c.

Neat! Need to try that some time, this isn't high priority for me
though.

> > > [SNIP]
> >
> > Maybe we should just set it in the CFLAGS directly then?
>
> We also don't control the CFLAGS the user is using.
>
> > Honestly, I am not entirely sure how you are supposed to do it
> > correctly. The thing is, if I do not set __KERNEL__, then I get the old
> > compatibility defines and types from asm/signal.h.
> >
> > And, I do not see an alternative way. It would not be safe to avoid the
> > include entirely and if you try that you are also missing the
> > SA_RESTORER define for the proper "struct sigaction" definition to be
> > correct.
> >
> > The best alternative I see would be copying the proper definitions into
> > the architecture specific header. That would also be ugly, as one would
> > need to do a "struct sigaction" -> "struct nolibc_rt_sigaction"
> > conversion internally. But, that would have the advantage that nolibc
> > works outside of the kernel tree.
>
> I think we need to do something like this.
> Luckily the real mess seems to be only on x86.

Right, if it is just x86, then it isn't too bad. "Just" needs some
header magic so that it doesn't get into the way of the user too much.

> > Even if all this is ugly, I would prefer that over using the
> > compatibility sigaction syscall instead of rt_sigaction.
>
> As an alternative, you are not forced to use nolibc for the KUnit UAPI
> framework. You can depend on CONFIG_CC_CAN_LINK_STATIC=y and use "-static" for
> the toolchains "real" libc.
> Not that I want to discourage you from contributing to nolibc, though.

Oh, I absolutely do not want to use glibc :-)

The thing is, I *really* want to use nolibc for the UM kernel itself
and drop glibc support entirely as glibc is a huge mess. For example,
the um kernel tries to override the malloc function to map it to
kmalloc after initialization. But then, that does not even work, and
glibc itself continues to use its own implementation … this kind of
stuff seems like a recipe for disaster.

Now, I don't mind doing raw syscalls in the um kernel. But basic signal
handling seems like a nice addition for nolibc.

Benjamin

Thomas Weißschuh

unread,
Jun 27, 2025, 4:43:40 AM6/27/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org
On Fri, Jun 27, 2025 at 09:29:12AM +0200, Benjamin Berg wrote:
> On Fri, 2025-06-27 at 06:33 +0200, Thomas Weißschuh wrote:
> > On Thu, Jun 26, 2025 at 09:57:12PM +0200, Benjamin Berg wrote:
> > > so I saw the UAPI testing framework patches and wondered whether I could
> > > hack up a kunit test for userspace signal mcontext handling. I already
> > > had some code, but never knew where to include it. Having it as a kunit
> > > test in this way seems nice as it makes running the test really simple.
> >
> > Nice to hear that you find it useful.
> >
> > > This is a very rough attempt with an extra patch to add sigaction
> > > support as that is needed by the test.
> > >
> > > Note that this type of test could possibly be shared with the x86
> > > architecture (though UM does not support all features).
> >
> > Can the expected feature detection be performed at runtime?
> > If so I would write the test as x86 kselftest in tools/testing/kselftests/x86/
> > and then also hook it up for kunit on UML and x86.
> > This gives you the advantages of all worlds.
> >
> > For an example see [0]. That is still based on an old version of the framework,
> > so can't be used as-is. But you should get the idea.
>
> That looks nice, and you do support both x86 and um there!
>
> Many of those checks should be simple as syscalls will return an error
> (modify_ldt should return -ENOSYS for example). For more arcane things
> one could e.g. add "(um)" into AT_PLATFORM or just disable the kunit
> test for the um architecture.

Sounds good.

> This is a nice development, I absolutely expect to find some bugs in um
> this way.

I do so, too :-)

https://lore.kernel.org/lkml/20250617-uml-tick-ti...@linutronix.de/

To be honest if there are going to be a bunch of issues on UML,
I'd prefer to drop the UML bits from my submissions.
I'm not familiar with UML and can't really fix the fallout.
Then you can wire up the tests with a few lines and handle the fallout at
your convenience.

Or we gate the testcases behind BROKEN/EXPORT on UML in the beginning.

Does this sound reasonable?

<snip>


Thomas

Benjamin Berg

unread,
Jun 27, 2025, 4:48:46 AM6/27/25
to Thomas Weißschuh, kuni...@googlegroups.com, linu...@lists.infradead.org
Hi,
Ah, yes, that one :-)

> To be honest if there are going to be a bunch of issues on UML,
> I'd prefer to drop the UML bits from my submissions.
> I'm not familiar with UML and can't really fix the fallout.
> Then you can wire up the tests with a few lines and handle the fallout at
> your convenience.
>
> Or we gate the testcases behind BROKEN/EXPORT on UML in the beginning.
>
> Does this sound reasonable?

Not sure how to gate them, but I do like the idea of being able to
enable them using only minor modifications or even a Kconfig option to
see what happens on UM.

Benjamin

>
> <snip>
>
>
> Thomas
>

Thomas Weißschuh

unread,
Jun 27, 2025, 5:23:03 AM6/27/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org
With my WIP x86 enablement commit as example [0].


Possibility 1, I *drop* these two hunks, you can readd them:

diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index 986045d5e63854..f2aeaf1e8e6d9a 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -3,6 +3,7 @@
menu "Host processor type and features"

source "arch/x86/Kconfig.cpu"
+source "arch/x86/tests/Kconfig"

endmenu

diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
index b42c31cd2390cb..e71bb244afac9d 100644
--- a/arch/x86/um/Makefile
+++ b/arch/x86/um/Makefile
@@ -13,7 +13,7 @@ obj-y = bugs_$(BITS).o delay.o fault.o \
ptrace.o ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \
stub_segv.o \
sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \
- mem_$(BITS).o subarch.o os-Linux/
+ mem_$(BITS).o subarch.o os-Linux/ ../tests/

ifeq ($(CONFIG_X86_32),y)


Possibility 2, the kconfig looks like this:

config X86_UAPI_TEST
tristate "x86 UAPI tests" if !KUNIT_ALL_TESTS
depends on KUNIT_UAPI
depends on !UML || BROKEN
default KUNIT_ALL_TESTS

You enable CONFIG_BROKEN and can run the tests.

Of course as soon as all tests work on UML, this all goes away and they
stay enabled.

[0] https://git.kernel.org/pub/scm/linux/kernel/git/thomas.weissschuh/linux.git/commit/?h=kunit-kselftests-integration&id=14bf93f09eaa328a18e9190f46fa4ee697378617

Benjamin Berg

unread,
Jun 27, 2025, 5:29:26 AM6/27/25
to Thomas Weißschuh, kuni...@googlegroups.com, linu...@lists.infradead.org
Hi,

On Fri, 2025-06-27 at 11:22 +0200, Thomas Weißschuh wrote:
> On Fri, Jun 27, 2025 at 10:48:30AM +0200, Benjamin Berg wrote:
> > Hi,
> >
> > On Fri, 2025-06-27 at 10:43 +0200, Thomas Weißschuh wrote:
> > > On Fri, Jun 27, 2025 at 09:29:12AM +0200, Benjamin Berg wrote:
> > > > > > [SNIP]
I think I prefer option 2. Not a strong opinion, but it shows that they
should be working just fine UML.

Benjamin

David Gow

unread,
Jul 2, 2025, 2:04:59 AM7/2/25
to Benjamin Berg, kuni...@googlegroups.com, linu...@lists.infradead.org, Thomas Weißschuh, Benjamin Berg
On Fri, 27 Jun 2025 at 03:59, Benjamin Berg <benj...@sipsolutions.net> wrote:
>
> From: Benjamin Berg <benjam...@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 <benjam...@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
Just to ruin your day, the SSE register stuff probably needs to be
behind some check for SSE support.
> --
> 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+...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/kunit-dev/20250626195714.2123694-3-benjamin%40sipsolutions.net.
Reply all
Reply to author
Forward
0 new messages