xenomai.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] [POC] test implementaion of rt-signals
@ 2023-05-09 13:13 Johannes Kirchmair
  2023-05-09 13:13 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-09 13:13 UTC (permalink / raw)
  To: xenomai; +Cc: johannes.kirchmair

We implement rt signals to handle exceptions in rt stage.

This is done using dovetail specific functions for setting up the signal
frame.

This can be used to handle fpe exceptions on the fly, like fixing
division by zero. An other use case are breakpoints, implemented using the
illegal opcode exception. The real time handling of the breakpoints would
be handy for conditional breakpoints or also for stopping watchdogs and
other tasks in time.

Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
---
 include/cobalt/kernel/ppd.h                   |  3 +
 include/cobalt/kernel/thread.h                |  2 +
 include/cobalt/signal.h                       |  2 +
 include/cobalt/uapi/syscall.h                 |  6 ++
 kernel/cobalt/arch/x86/Makefile               |  2 +-
 .../arch/x86/include/asm/xenomai/thread.h     | 13 ++++
 kernel/cobalt/arch/x86/signal_ia32.c          | 75 +++++++++++++++++++
 kernel/cobalt/arch/x86/signal_ia64.c          | 26 +++++++
 kernel/cobalt/dovetail/kevents.c              |  5 ++
 kernel/cobalt/posix/process.c                 |  3 +-
 kernel/cobalt/posix/syscall.c                 | 28 +++++++
 kernel/cobalt/posix/syscall32.c               | 16 ++++
 kernel/cobalt/thread.c                        | 39 ++++++++++
 lib/cobalt/arch/x86/Makefile.am               |  2 +-
 lib/cobalt/arch/x86/sigreturn.c               | 32 ++++++++
 lib/cobalt/internal.h                         |  2 +
 lib/cobalt/signal.c                           | 13 ++++
 17 files changed, 266 insertions(+), 3 deletions(-)
 create mode 100644 kernel/cobalt/arch/x86/signal_ia32.c
 create mode 100644 kernel/cobalt/arch/x86/signal_ia64.c
 create mode 100644 lib/cobalt/arch/x86/sigreturn.c

diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
index f0079fe6e..fb2f682da 100644
--- a/include/cobalt/kernel/ppd.h
+++ b/include/cobalt/kernel/ppd.h
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 #include <linux/atomic.h>
 #include <linux/rbtree.h>
+#include <linux/signal.h>
 #include <cobalt/kernel/heap.h>
 
 struct cobalt_umm {
@@ -32,6 +33,8 @@ struct cobalt_umm {
 
 struct cobalt_ppd {
 	struct cobalt_umm umm;
+	void __user *sighand[_NSIG];
+	void __user *sigrestorer;
 	atomic_t refcnt;
 	char *exe_path;
 	struct rb_root fds;
diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
index b79cb8429..33d468419 100644
--- a/include/cobalt/kernel/thread.h
+++ b/include/cobalt/kernel/thread.h
@@ -574,6 +574,8 @@ static inline void xnthread_propagate_schedparam(struct xnthread *curr)
 		__xnthread_propagate_schedparam(curr);
 }
 
+int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
+
 extern struct xnthread_personality xenomai_personality;
 
 /** @} */
diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
index 62694f93a..3d6540aff 100644
--- a/include/cobalt/signal.h
+++ b/include/cobalt/signal.h
@@ -54,6 +54,8 @@ COBALT_DECL(int, kill(pid_t pid, int sig));
 COBALT_DECL(int, sigqueue(pid_t pid, int sig,
 			  const union sigval value));
 
+int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index 9646a0d97..6307fae7f 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -137,6 +137,12 @@
 #define sc_cobalt_recvmmsg64			114
 #define sc_cobalt_cond_wait_prologue64		115
 
+/*
+ * Sigmatek specific syscalls
+ */
+#define sc_cobalt_sigreturn			120
+#define sc_cobalt_sigaction			121
+
 #define __NR_COBALT_SYSCALLS			128 /* Power of 2 */
 
 #endif /* !_COBALT_UAPI_SYSCALL_H */
diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
index 93929b645..e725afbff 100644
--- a/kernel/cobalt/arch/x86/Makefile
+++ b/kernel/cobalt/arch/x86/Makefile
@@ -1,5 +1,5 @@
 
 obj-$(CONFIG_XENOMAI) += xenomai.o
-xenomai-y := machine.o smi.o c1e.o
+xenomai-y := machine.o smi.o c1e.o signal_ia32.o signal_ia64.o
 
 ccflags-y := -I$(srctree)/arch/x86/xenomai/include -I$(srctree)/include/xenomai
diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
index 745c32467..4d004680b 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
@@ -28,5 +28,18 @@
 #define xnarch_fault_bp_p(__nr)		((current->ptrace & PT_PTRACED) &&	\
 					 ((__nr) == X86_TRAP_DB || (__nr) == X86_TRAP_BP))
 #define xnarch_fault_notify(__nr)	(!xnarch_fault_bp_p(__nr))
+#define xnarch_fault_code(__regs)		((__regs)->orig_ax)
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+			   long errcode, int *sig, struct kernel_siginfo *info);
+
+int xnarch_setup_rt_frame_ia32(int sig, void *handler, struct kernel_siginfo *si,
+			  struct pt_regs *regs, void __user *restorer);
+
+int xnarch_rt_sigreturn_ia32(struct pt_regs *regs);
+
+int xnarch_setup_rt_frame_ia64(int sig, void *handler, struct kernel_siginfo *si,
+			  struct pt_regs *regs, void __user *restorer);
+
+int xnarch_rt_sigreturn_ia64(struct pt_regs *regs);
 
 #endif /* !_COBALT_X86_ASM_THREAD_H */
diff --git a/kernel/cobalt/arch/x86/signal_ia32.c b/kernel/cobalt/arch/x86/signal_ia32.c
new file mode 100644
index 000000000..e78c8c4d4
--- /dev/null
+++ b/kernel/cobalt/arch/x86/signal_ia32.c
@@ -0,0 +1,75 @@
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+#include <cobalt/kernel/thread.h>
+
+#include <asm/sigframe.h>
+#include <asm/sighandling.h>
+#include <asm/fpu/signal.h>
+
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+			   long errcode, int *sig, struct kernel_siginfo *info)
+{
+	switch (vector) {
+	case 0: /* divide_error */
+		*sig = SIGFPE;
+		info->si_signo = *sig;
+		info->si_errno = 0;
+		info->si_code = FPE_INTDIV;
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+	case 1: /* trap_error */ {
+		unsigned long condition;
+		get_debugreg(condition, 6);
+		set_debugreg(0, 7);
+		*sig = SIGTRAP;
+		info->si_signo = *sig;
+		info->si_errno = errcode;
+		info->si_code = get_si_code(condition);
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+	}
+	case 3: /* trap_error */
+		*sig = SIGTRAP;
+		info->si_signo = *sig;
+		info->si_errno = errcode;
+		info->si_code = SI_KERNEL;
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+	case 6: /* invalid_op */
+		*sig = SIGILL;
+		info->si_signo = *sig;
+		info->si_errno = 0;
+		info->si_code = ILL_ILLOPN;
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+	case 16: { /* coprocessor_error */
+		*sig = SIGFPE;
+
+		info->si_signo = *sig;
+		info->si_errno = 0;
+		info->si_code = 0;
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+	}
+	default:
+		break;
+	}
+
+	return -ENOSYS;
+}
+
+int xnarch_rt_sigreturn_ia32(struct pt_regs *regs)
+{
+	int ret;
+
+	ret = dovetail_restore_rt_signal_frame(regs);
+	if (ret < 0)
+		goto badframe;
+
+	return regs->ax;
+
+badframe:
+	xnthread_call_mayday(xnthread_current(), SIGKILL);
+	return -1;
+}
+
diff --git a/kernel/cobalt/arch/x86/signal_ia64.c b/kernel/cobalt/arch/x86/signal_ia64.c
new file mode 100644
index 000000000..a7044db40
--- /dev/null
+++ b/kernel/cobalt/arch/x86/signal_ia64.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ *  2000-2002   x86-64 support by Andi Kleen
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+#include <cobalt/kernel/thread.h>
+
+#include <asm/sigframe.h>
+#include <asm/sighandling.h>
+#include <asm/fpu/signal.h>
+
+int xnarch_rt_sigreturn_ia64(struct pt_regs *regs)
+{
+	return dovetail_restore_rt_signal_frame(regs);
+}
+
diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
index 4da4f51b7..61417717b 100644
--- a/kernel/cobalt/dovetail/kevents.c
+++ b/kernel/cobalt/dovetail/kevents.c
@@ -57,6 +57,9 @@ void handle_oob_trap_entry(unsigned int trapnr, struct pt_regs *regs)
 		xnsched_run();
 	}
 
+	if (xnthread_handle_rt_signals(trapnr, regs) == 0)
+		return;
+
 	/*
 	 * If we experienced a trap on behalf of a shadow thread
 	 * running in primary mode, move it to the Linux domain,
@@ -88,6 +91,8 @@ void handle_oob_trap_entry(unsigned int trapnr, struct pt_regs *regs)
 		xnstat_counter_inc(&thread->stat.pf);
 
 	xnthread_relax(xnarch_fault_notify(trapnr), SIGDEBUG_MIGRATE_FAULT);
+
+	return;
 }
 
 static inline int handle_setaffinity_event(struct dovetail_migration_data *d)
diff --git a/kernel/cobalt/posix/process.c b/kernel/cobalt/posix/process.c
index 1abc86f37..2069129cb 100644
--- a/kernel/cobalt/posix/process.c
+++ b/kernel/cobalt/posix/process.c
@@ -738,9 +738,10 @@ void cobalt_unregister_debugged_thread(struct xnthread *thread)
 		cobalt_resume_debugged_process(process);
 }
 
+#ifdef CONFIG_SMP
+
 int cobalt_handle_setaffinity_event(struct task_struct *task)
 {
-#ifdef CONFIG_SMP
 	struct xnthread *thread;
 	spl_t s;
 
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 46c4998e4..b4bd4c587 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -277,6 +277,34 @@ static COBALT_SYSCALL(serialdbg, current,
 	return 0;
 }
 
+static COBALT_SYSCALL(sigreturn, current, (void))
+{
+	struct pt_regs *regs = task_pt_regs(current);
+
+	if (regs->cs == __USER_CS)
+		xnarch_rt_sigreturn_ia64(regs);
+	if (regs->cs == __USER32_CS)
+		xnarch_rt_sigreturn_ia32(regs);
+
+	return __xn_reg_rval(regs);
+}
+
+static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
+		      void __user *restorer))
+{
+	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
+
+	if (sig < 0 || sig >= _NSIG)
+		return -EINVAL;
+
+	sys_ppd->sighand[sig] = handler;
+
+	if (!sys_ppd->sigrestorer)
+		sys_ppd->sigrestorer = restorer;
+
+	return 0;
+}
+
 static void stringify_feature_set(unsigned long fset, char *buf, int size)
 {
 	unsigned long feature;
diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
index b65a0a760..f8b21bfb2 100644
--- a/kernel/cobalt/posix/syscall32.c
+++ b/kernel/cobalt/posix/syscall32.c
@@ -774,6 +774,22 @@ COBALT_SYSCALL32emu(sigqueue, conforming,
 	return ret ?: __cobalt_sigqueue(pid, sig, &val);
 }
 
+COBALT_SYSCALL32emu(sigaction, current,
+		    (int sig, void __user *handler, void __user *restorer))
+{
+	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
+
+	if (sig < 0 || sig >= _NSIG)
+		return -EINVAL;
+
+	sys_ppd->sighand[sig] = handler;
+
+	if (!sys_ppd->sigrestorer)
+		sys_ppd->sigrestorer = restorer;
+
+	return 0;
+}
+
 COBALT_SYSCALL32emu(monitor_wait, nonrestartable,
 		    (struct cobalt_monitor_shadow __user *u_mon,
 		     int event, const struct old_timespec32 __user *u_ts,
diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
index 41804b24f..71f97c481 100644
--- a/kernel/cobalt/thread.c
+++ b/kernel/cobalt/thread.c
@@ -25,6 +25,7 @@
 #include <linux/signal.h>
 #include <linux/pid.h>
 #include <linux/sched.h>
+#include <asm/sighandling.h>
 #include <uapi/linux/sched/types.h>
 #include <cobalt/kernel/sched.h>
 #include <cobalt/kernel/timer.h>
@@ -43,6 +44,7 @@
 #include <pipeline/inband_work.h>
 #include <pipeline/sched.h>
 #include <trace/events/cobalt-core.h>
+#include "posix/process.h"
 #include "debug.h"
 
 static DECLARE_WAIT_QUEUE_HEAD(join_all);
@@ -2520,6 +2522,43 @@ int xnthread_killall(int grace, int mask)
 }
 EXPORT_SYMBOL_GPL(xnthread_killall);
 
+int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
+{
+	struct ksignal ksig;
+
+	unsigned int vector = trapnr;
+	unsigned int code = xnarch_fault_code(regs);
+	struct cobalt_ppd *sys_ppd;
+	int sig, ret = 0;
+	struct kernel_siginfo si;
+
+	code = xnarch_fault_code(regs);
+	ret = xnarch_setup_trap_info(vector, regs, code, &sig, &si);
+	if (ret || sig == 0)
+		return 1;
+
+	sys_ppd = cobalt_ppd_get(0);
+	if (sig >= _NSIG ||
+	    sys_ppd->sighand[sig] == NULL ||
+	    sys_ppd->sighand[sig] == SIG_DFL)
+		return 1;
+
+	if (sys_ppd->sigrestorer == NULL)
+		return 1;
+
+	ksig.sig = sig;
+	memcpy(&ksig.info, &si, sizeof(si));
+	ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
+	ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
+	ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
+
+	ret = dovetail_setup_rt_signal_frame(&ksig, regs);
+	if (ret)
+		return 1;
+
+	return 0;
+}
+
 /* Xenomai's generic personality. */
 struct xnthread_personality xenomai_personality = {
 	.name = "core",
diff --git a/lib/cobalt/arch/x86/Makefile.am b/lib/cobalt/arch/x86/Makefile.am
index a5095be3d..14f5eff97 100644
--- a/lib/cobalt/arch/x86/Makefile.am
+++ b/lib/cobalt/arch/x86/Makefile.am
@@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarch.la
 
 libarch_la_LDFLAGS = @XENO_LIB_LDFLAGS@
 
-libarch_la_SOURCES = features.c
+libarch_la_SOURCES = features.c sigreturn.c
 
 libarch_la_CPPFLAGS =			\
 	@XENO_COBALT_CFLAGS@ 		\
diff --git a/lib/cobalt/arch/x86/sigreturn.c b/lib/cobalt/arch/x86/sigreturn.c
new file mode 100644
index 000000000..76292e145
--- /dev/null
+++ b/lib/cobalt/arch/x86/sigreturn.c
@@ -0,0 +1,32 @@
+#include <cobalt/uapi/syscall.h>
+#include "internal.h"
+
+extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__ ((visibility ("hidden")));
+
+#ifdef __x86_64__
+#define build_restorer(syscall_number)                                         \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movq $ " #syscall_number ", %rax\n"                           \
+	    "    syscall")
+#endif
+
+#ifdef __i386__
+#define build_restorer(syscall_number)                                         \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movl $ " #syscall_number ", %eax\n"                           \
+	    "    int  $0x80")
+#endif
+
+/*
+ * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
+ */
+build_restorer(0x10000078);
+
+void *cobalt_get_restorer(void)
+{
+	return &cobalt_sigreturn;
+}
diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
index acb3989f1..4782d154a 100644
--- a/lib/cobalt/internal.h
+++ b/lib/cobalt/internal.h
@@ -132,4 +132,6 @@ static inline bool cobalt_features_available(unsigned int feat_mask)
 	return (cobalt_features & feat_mask) == feat_mask;
 }
 
+extern void *cobalt_get_restorer(void);
+
 #endif /* _LIB_COBALT_INTERNAL_H */
diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
index 40d315ebb..af174d570 100644
--- a/lib/cobalt/signal.c
+++ b/lib/cobalt/signal.c
@@ -126,3 +126,16 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const union sigval value))
 
 	return 0;
 }
+
+int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
+{
+	int ret;
+
+	ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler, cobalt_get_restorer());
+	if (ret) {
+		errno = -ret;
+		return -1;
+	}
+
+	return 0;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] [POC] Add rt_signal test
  2023-05-09 13:13 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
@ 2023-05-09 13:13 ` Johannes Kirchmair
  2023-05-09 13:13 ` [PATCH 3/3] [POC] add a tool to measure rt_signal latency Johannes Kirchmair
  2023-05-09 13:17 ` [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
  2 siblings, 0 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-09 13:13 UTC (permalink / raw)
  To: xenomai; +Cc: johannes.kirchmair

This commit adds simple rt signal test for SIGFPE, SIGILL and SIGSEGV.
---
 configure.ac                               |   1 +
 testsuite/Makefile.am                      |   1 +
 testsuite/rt-signal-tests/Makefile.am      |  31 +++
 testsuite/rt-signal-tests/rt_signal_test.c | 228 +++++++++++++++++++++
 4 files changed, 261 insertions(+)
 create mode 100644 testsuite/rt-signal-tests/Makefile.am
 create mode 100644 testsuite/rt-signal-tests/rt_signal_test.c

diff --git a/configure.ac b/configure.ac
index 3ce34048e..3325482fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1007,6 +1007,7 @@ AC_CONFIG_FILES([ \
 	testsuite/switchtest/Makefile \
 	testsuite/gpiotest/Makefile \
 	testsuite/gpiobench/Makefile \
+	testsuite/rt-signal-tests/Makefile \
 	testsuite/spitest/Makefile \
 	testsuite/smokey/Makefile \
 	testsuite/smokey/arith/Makefile \
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 4932f6d33..59f36967a 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -5,6 +5,7 @@ if XENO_COBALT
 SUBDIRS += 		\
 	clocktest	\
 	gpiotest	\
+	rt-signal-tests	\
 	spitest		\
 	switchtest	\
 	xeno-test
diff --git a/testsuite/rt-signal-tests/Makefile.am b/testsuite/rt-signal-tests/Makefile.am
new file mode 100644
index 000000000..084347631
--- /dev/null
+++ b/testsuite/rt-signal-tests/Makefile.am
@@ -0,0 +1,31 @@
+testdir = @XENO_TEST_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rt_signal_test_fpe rt_signal_test_segfault rt_signal_test_ill
+
+alchemycppflags =              			 \
+	$(XENO_USER_CFLAGS)    			 \
+	-I$(top_srcdir)/include
+
+alchemyldadd =					\
+	@XENO_AUTOINIT_LDFLAGS@			\
+	$(XENO_POSIX_WRAPPERS)			\
+	../../lib/alchemy/libalchemy.la		\
+	../../lib/copperplate/libcopperplate.la	\
+	@XENO_CORE_LDADD@			\
+	@XENO_USER_LDADD@			\
+	-lrt -lpthread -lm
+
+rt_signal_test_fpe_SOURCES = rt_signal_test.c
+rt_signal_test_fpe_CPPFLAGS = $(alchemycppflags) -DTEST_FPE=1
+rt_signal_test_fpe_LDADD = $(alchemyldadd)
+
+rt_signal_test_segfault_SOURCES = rt_signal_test.c
+rt_signal_test_segfault_CPPFLAGS = $(alchemycppflags) -DTEST_SEGFAULT=1
+rt_signal_test_segfault_LDADD = $(alchemyldadd)
+
+rt_signal_test_ill_SOURCES = rt_signal_test.c
+rt_signal_test_ill_CPPFLAGS = $(alchemycppflags)
+rt_signal_test_ill_LDADD = $(alchemyldadd)
+
diff --git a/testsuite/rt-signal-tests/rt_signal_test.c b/testsuite/rt-signal-tests/rt_signal_test.c
new file mode 100644
index 000000000..0d43ac8da
--- /dev/null
+++ b/testsuite/rt-signal-tests/rt_signal_test.c
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <copperplate/traceobj.h>
+#include <alchemy/task.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <asm/ucontext.h>
+
+#ifdef TEST_SEGFAULT
+#define TEST_SIGNAL SIGSEGV
+#elif defined(TEST_FPE)
+#define TEST_SIGNAL SIGFPE
+#else
+#define TEST_SIGNAL SIGILL
+#endif
+
+#define BIT_FAULT_HANDLER_ENTERD     1
+#define BIT_FAULT_HANDLER_FINISHED   2
+#define BIT_FAULT_HANDLER_WRONG_TASK 4
+#define BIT_FAULT_HANDLER_WRONG_SIG  8
+#define BIT_DOMAIN_SWITCH            16
+
+static RT_TASK t1;
+static sig_atomic_t status = 0;
+static sig_atomic_t cause = 0;
+
+// #define JMP_CLEANUP
+#ifdef JMP_CLEANUP
+static jmp_buf jmpenv;
+#endif
+
+static int status_ok(void)
+{
+	return status ==
+	       (BIT_FAULT_HANDLER_ENTERD | BIT_FAULT_HANDLER_FINISHED);
+}
+
+static const char *sigdebug_msg[] = {
+	[SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
+	[SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+	[SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+	[SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+	[SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
+	[SIGDEBUG_NOMLOCK] = "Xenomai: process memory not locked "
+			     "(missing mlockall?)",
+	[SIGDEBUG_WATCHDOG] = "Xenomai: watchdog triggered "
+			      "(period too short?)",
+};
+
+
+#ifndef JMP_CLEANUP
+static int get_step(void)
+{
+#ifdef TEST_SEGFAULT
+#if defined(__i386__) || defined(__x86_64__)
+	return 11;
+#else
+	return 4;
+#endif
+#elif defined(TEST_FPE)
+	return 2;
+#else
+#if defined(__i386__) || defined(__x86_64__)
+	return 2;
+#else
+	return 4;
+#endif
+#endif
+}
+
+static void do_cleanup(void *context)
+{
+	int step = 0;
+	struct ucontext *uc = context;
+
+	step = get_step();
+
+#if defined(__i386__)
+	uc->uc_mcontext.eip += step;
+#elif defined(__x86_64__)
+	uc->uc_mcontext.rip += step;
+#elif defined(__aarch64__)
+	uc->uc_mcontext.pc += step;
+#endif
+}
+#endif
+
+static void signal_handler(int sig, siginfo_t *info, void *context)
+{
+	RT_TASK *self;
+	(void)context;
+
+	if (sig == SIGDEBUG) {
+		cause = sigdebug_reason(info);
+
+		if (cause > SIGDEBUG_WATCHDOG)
+			cause = SIGDEBUG_UNDEFINED;
+
+		/* XXX: caused by rt_task_delete() */
+		if (!(status & BIT_FAULT_HANDLER_ENTERD) &&
+		    cause == SIGDEBUG_MIGRATE_SYSCALL) {
+			return;
+		}
+
+		status |= BIT_DOMAIN_SWITCH;
+	} else {
+		status |= BIT_FAULT_HANDLER_ENTERD;
+		if (sig != TEST_SIGNAL) {
+			status |= BIT_FAULT_HANDLER_WRONG_SIG;
+			return;
+		}
+
+		self = rt_task_self();
+
+		if (self == NULL || !rt_task_same(self, &t1)) {
+			status |= BIT_FAULT_HANDLER_WRONG_TASK;
+		} else {
+			status |= BIT_FAULT_HANDLER_FINISHED;
+		}
+
+#ifdef JMP_CLEANUP
+		longjmp(jmpenv, 1);
+#else
+		do_cleanup(context);
+#endif
+	}
+}
+
+static void do_div_by_0(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("xorl %eax, %eax\n\t"
+		"movl %eax, %ecx\n\t"
+		"cltd\n\t"
+		"idivl %ecx");
+#endif
+	//TODO find a cortex-A way to trigger an FPE
+}
+
+static void do_ill(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("ud2");
+#else
+	__asm__("udf #0xdead");
+#endif
+}
+
+static void do_segfault(void)
+{
+	*((int *)0x73) = 0xdecafbad;
+}
+
+static void task_proc(void *arg)
+{
+	int ret;
+	(void)arg;
+
+	ret = cobalt_rt_signal(TEST_SIGNAL, signal_handler);
+	assert(ret == 0);
+	(void)ret;
+
+#ifdef JMP_CLEANUP
+	if (setjmp(jmpenv) != 0)
+		return;
+#endif
+
+#ifdef TEST_SEGFAULT
+	do_segfault();
+#elif defined(TEST_FPE)
+	do_div_by_0();
+#else
+	do_ill();
+#endif
+
+	if (0) { // so we don't geht defined but not used errors
+		do_segfault();
+		do_div_by_0();
+		do_ill();
+	}
+}
+
+static int test_sucessfull(void)
+{
+	if (status_ok()) {
+		fputs("Test passed\n", stderr);
+		return 1;
+	}
+
+	if (!(status & BIT_FAULT_HANDLER_ENTERD))
+		fputs("Test failed: signal handler not invoked!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_TASK))
+		fputs("Test failed: Signal handler in wrong task!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_SIG))
+		fputs("Test failed: Signal handler of wrong signal!\n", stderr);
+	if ((status & BIT_DOMAIN_SWITCH)) {
+		fputs("Test failed: domain switch happened!\n", stderr);
+		fprintf(stderr, "Caused by: %s\n", sigdebug_msg[cause]);
+	}
+
+	return 0;
+}
+
+int main(void)
+{
+	struct sigaction sa;
+	int ret;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = signal_handler;
+	sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+	sigaction(TEST_SIGNAL, &sa, NULL);
+	sigaction(SIGDEBUG, &sa, NULL);
+
+	ret = rt_task_create(&t1, "rt-task", 0, 20, T_JOINABLE | T_WARNSW);
+	assert(ret == 0);
+
+	ret = rt_task_start(&t1, task_proc, NULL);
+	assert(ret == 0);
+
+	ret = rt_task_join(&t1);
+	assert(ret == 0);
+	(void)ret; // so the compiler does not complain about not checking ret
+
+	return test_sucessfull() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] [POC] add a tool to measure rt_signal latency
  2023-05-09 13:13 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
  2023-05-09 13:13 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair
@ 2023-05-09 13:13 ` Johannes Kirchmair
  2023-05-09 13:17 ` [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
  2 siblings, 0 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-09 13:13 UTC (permalink / raw)
  To: xenomai; +Cc: johannes.kirchmair

Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
---
 configure.ac                          |   1 +
 utils/Makefile.am                     |   2 +-
 utils/rt_signal_hist/Makefile.am      |  22 ++++
 utils/rt_signal_hist/error.h          |  14 +++
 utils/rt_signal_hist/histo.c          |  46 ++++++++
 utils/rt_signal_hist/histo.h          |  13 +++
 utils/rt_signal_hist/result.c         |  16 +++
 utils/rt_signal_hist/result.h         |  12 ++
 utils/rt_signal_hist/rt_signal_hist.c | 158 ++++++++++++++++++++++++++
 9 files changed, 283 insertions(+), 1 deletion(-)
 create mode 100644 utils/rt_signal_hist/Makefile.am
 create mode 100644 utils/rt_signal_hist/error.h
 create mode 100644 utils/rt_signal_hist/histo.c
 create mode 100644 utils/rt_signal_hist/histo.h
 create mode 100644 utils/rt_signal_hist/result.c
 create mode 100644 utils/rt_signal_hist/result.h
 create mode 100644 utils/rt_signal_hist/rt_signal_hist.c

diff --git a/configure.ac b/configure.ac
index 3325482fc..fe4a3b3e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1054,6 +1054,7 @@ AC_CONFIG_FILES([ \
 	utils/slackspot/Makefile \
 	utils/corectl/Makefile \
 	utils/autotune/Makefile \
+	utils/rt_signal_hist/Makefile \
 	utils/net/rtnet \
 	utils/net/rtnet.conf \
 	utils/net/Makefile \
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 4de6434a9..79c39ac90 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -1,5 +1,5 @@
 SUBDIRS = hdb
 if XENO_COBALT
-SUBDIRS += analogy autotune can net ps slackspot corectl
+SUBDIRS += analogy autotune can net ps slackspot corectl rt_signal_hist
 endif
 SUBDIRS += chkkconf
diff --git a/utils/rt_signal_hist/Makefile.am b/utils/rt_signal_hist/Makefile.am
new file mode 100644
index 000000000..810a63bba
--- /dev/null
+++ b/utils/rt_signal_hist/Makefile.am
@@ -0,0 +1,22 @@
+testdir = @XENO_TEST_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rt_signal_hist
+
+alchemycppflags =              			 \
+	$(XENO_USER_CFLAGS)    			 \
+	-I$(top_srcdir)/include
+
+alchemyldadd =					\
+	@XENO_AUTOINIT_LDFLAGS@			\
+	$(XENO_POSIX_WRAPPERS)			\
+	../../lib/alchemy/libalchemy.la		\
+	../../lib/copperplate/libcopperplate.la	\
+	@XENO_CORE_LDADD@			\
+	@XENO_USER_LDADD@			\
+	-lrt -lpthread -lm
+
+rt_signal_hist_SOURCES = rt_signal_hist.c histo.c result.c
+rt_signal_hist_CPPFLAGS = $(alchemycppflags)
+rt_signal_hist_LDADD = $(alchemyldadd)
diff --git a/utils/rt_signal_hist/error.h b/utils/rt_signal_hist/error.h
new file mode 100644
index 000000000..4aa50e70e
--- /dev/null
+++ b/utils/rt_signal_hist/error.h
@@ -0,0 +1,14 @@
+#ifndef ERROR_EXIT_H
+#define ERROR_EXIT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int error(char *reason, int ret)
+{
+	printf("%s: err= %d\n", reason, ret);
+	exit(1);
+}
+
+#endif
+
diff --git a/utils/rt_signal_hist/histo.c b/utils/rt_signal_hist/histo.c
new file mode 100644
index 000000000..36e51201b
--- /dev/null
+++ b/utils/rt_signal_hist/histo.c
@@ -0,0 +1,46 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "histo.h"
+#include "error.h"
+
+void initHisto(struct histo **histo, unsigned long n)
+{
+	int i = 0;
+	*histo = malloc(sizeof(struct histo) + n * sizeof(unsigned long));
+	if (!histo)
+		return;
+
+	for (i = 0; i < n; ++i) {
+		(*histo)->data[i] = 0;
+	}
+	(*histo)->max_index = 0;
+	(*histo)->n = n;
+}
+
+void writeHisto(struct histo *histo)
+{
+	unsigned long i;
+	FILE *f = fopen("hist.txt", "w");
+	if (!f)
+		error("can't open \"hist.txt\n", errno);
+
+	for (i = 0; i <= histo->max_index; ++i) {
+		fprintf(f, "%lu %lu\n", i, histo->data[i]);
+	}
+
+	fclose(f);
+}
+
+void updateHisto(struct histo *histo, unsigned long curr)
+{
+	unsigned long index;
+
+	index = curr;
+	index = index >= histo->n ? histo->n - 1 : index;
+
+	histo->max_index = histo->max_index >= index ? histo->max_index : index;
+	histo->data[index]++;
+}
+
diff --git a/utils/rt_signal_hist/histo.h b/utils/rt_signal_hist/histo.h
new file mode 100644
index 000000000..63c92014a
--- /dev/null
+++ b/utils/rt_signal_hist/histo.h
@@ -0,0 +1,13 @@
+#ifndef HISTO_H
+#define HISTO_H
+
+struct histo {
+	unsigned long n;
+	unsigned long max_index;
+	unsigned long data[];
+};
+
+void initHisto(struct histo **histo, unsigned long n);
+void writeHisto(struct histo *histo);
+void updateHisto(struct histo *histo, unsigned long curr);
+#endif
diff --git a/utils/rt_signal_hist/result.c b/utils/rt_signal_hist/result.c
new file mode 100644
index 000000000..a863d7182
--- /dev/null
+++ b/utils/rt_signal_hist/result.c
@@ -0,0 +1,16 @@
+#include "result.h"
+
+void initResult(struct result *resu)
+{
+	resu->min = (unsigned long)-1l;
+	resu->max = 0ul;
+	resu->avr = 0ul;
+}
+
+void updateResult(struct result *resu, unsigned long curr, unsigned long ith_entry)
+{
+	resu->min = curr < resu->min ? curr: resu->min;
+	resu->max = curr > resu->max ? curr: resu->max;
+	resu->avr = (resu->avr *(ith_entry - 1) + curr) / ith_entry;
+}
+
diff --git a/utils/rt_signal_hist/result.h b/utils/rt_signal_hist/result.h
new file mode 100644
index 000000000..9895535ee
--- /dev/null
+++ b/utils/rt_signal_hist/result.h
@@ -0,0 +1,12 @@
+#ifndef RESULT_H
+#define RESULT_H
+
+struct result {
+	unsigned long min;
+	unsigned long max;
+	unsigned long avr;
+};
+
+void initResult(struct result *resu);
+void updateResult(struct result *resu, unsigned long curr, unsigned long ith_entry);
+#endif
diff --git a/utils/rt_signal_hist/rt_signal_hist.c b/utils/rt_signal_hist/rt_signal_hist.c
new file mode 100644
index 000000000..076084e9e
--- /dev/null
+++ b/utils/rt_signal_hist/rt_signal_hist.c
@@ -0,0 +1,158 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <asm/ucontext.h>
+
+#include <alchemy/task.h>
+#include <cobalt/signal.h>
+#include <copperplate/clockobj.h>
+
+#include "histo.h"
+#include "result.h"
+#include "error.h"
+
+#define TEST_SIGNAL SIGILL
+#define USE_GETTIME 0
+#define USE_RT_SIGNALS 1
+
+static RT_TASK task;
+
+static void do_cleanup(void *context)
+{
+	struct ucontext *uc = context;
+
+#if defined(__i386__)
+	uc->uc_mcontext.eip += 2;
+#elif defined(__x86_64__)
+	uc->uc_mcontext.rip += 2;
+#else
+	uc->uc_mcontext.pc += 4;
+#endif
+}
+
+static void sighandler(int sig, siginfo_t *info, void *data)
+{
+	do_cleanup(data);
+}
+
+static void do_ill(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("ud2");
+#else
+	__asm__("udf #0xdead");
+#endif
+}
+
+static void registerSignal(void)
+{
+	int ret;
+
+	ret = cobalt_rt_signal(TEST_SIGNAL, sighandler);
+	if (ret)
+		error("cobalt_rt_signal", ret);
+}
+
+static void printPreRunInfo(void)
+{
+	if (USE_GETTIME) {
+		struct timespec time;
+		clock_getres(CLOCK_MONOTONIC_RAW, &time);
+		printf("res_sec = %ld res_nsec = %ld \n", time.tv_sec, time.tv_nsec);
+	} else {
+		printf("res_nsec = %lld\n", clockobj_tsc_to_ns(1));
+	}
+}
+
+static inline unsigned long ns_now(void)
+{
+	if (USE_GETTIME) {
+		struct timespec time;
+		clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+		return time.tv_nsec;
+	} else {
+		ticks_t ticks;
+		ticks = clockobj_get_tsc();
+		return clockobj_tsc_to_ns(ticks);
+	}
+}
+
+static void task_func(void *cookie)
+{
+	struct histo *histo = (struct histo *)cookie;
+	struct result resu;
+
+	unsigned long start, stop, curr;
+	int i, j;
+
+	printPreRunInfo();
+
+	registerSignal();
+
+	initResult(&resu);
+
+	for (j = 0; j < 10000; ++j) {
+		for (i = 0; i < 1000; ++i) {
+
+			start = ns_now();
+			do_ill();
+			stop = ns_now();
+
+			if (stop <= start) { // dismiss on counter overrun
+				continue;
+			}
+
+			curr = stop - start;
+
+			updateResult(&resu, curr, i+1); // + 1 as we add with index i the (i+1)th entry
+
+			updateHisto(histo, curr);
+		}
+
+		printf("min = %lu max = %lu avr = %lu\n", resu.min, resu.max, resu.avr);
+		rt_task_sleep(1000000);
+	}
+}
+
+static const char *task_name = "signal_test_task";
+static const int prio = 80;
+
+int main(int argc, char **argv)
+{
+	int ret;
+	struct histo *histo;
+
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = sighandler;
+	sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+	sigaction(TEST_SIGNAL, &sa, NULL);
+
+	initHisto(&histo, 100000000);
+	if (!histo)
+		error("could not init histo", -ENOMEM);
+
+	ret = rt_task_create(&task, task_name, 0, prio, T_JOINABLE);
+	if (ret)
+		error("rt_task_create", ret);
+
+	ret = rt_task_start(&task, task_func, histo);
+	if (ret)
+		error("cant start task", ret);
+
+	rt_task_join(&task);
+	rt_task_delete(&task);
+
+	writeHisto(histo);
+
+	return 0;
+}
+
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-09 13:13 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
  2023-05-09 13:13 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair
  2023-05-09 13:13 ` [PATCH 3/3] [POC] add a tool to measure rt_signal latency Johannes Kirchmair
@ 2023-05-09 13:17 ` Johannes Kirchmair
  2023-05-12 17:38   ` Jan Kiszka
  2023-08-09  9:50   ` Schaffner, Tobias
  2 siblings, 2 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-09 13:17 UTC (permalink / raw)
  To: xenomai, Schaffner, Tobias, Jan Kiszka

Hello Jan and Tobias,

I just dropped the patches on the mailing list.
For the dovetail functions I took a rather naive approach, using most of the frame setup code provided by Linux.
I just tested it for 32bit and 64bit x86 Applications and it seems to work. 

I also added a tool rt_signal_hist that runs in a cycle and measures the time an exception handling takes.
It is afterwards put into an txt file that reassembles an histogram of the timings.

Unfortunately as a 32bit application the rt_signal_hist tool does not run to completion, printing the following:
" Xenomai/cobalt: sleeping while holding mutex
CPU time limit exceeded"

Maybe the naive approach is not so reliable ;-/
Hope I find the time the look into it. 

Sorry for not putting more effort into this so fare.

The next most important step in my opinion would be to define a clean interface into dovetail for the signal frame setup and restoring.
Actually that's the task I consider one of the harder and I am not so sure how to approach this.

Best regards
Johannes

> -----Original Message-----
> From: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> Sent: Dienstag, 9. Mai 2023 15:14
> To: xenomai@lists.linux.dev
> Cc: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> Subject: [PATCH 1/3] [POC] test implementaion of rt-signals
> 
> We implement rt signals to handle exceptions in rt stage.
> 
> This is done using dovetail specific functions for setting up the signal
> frame.
> 
> This can be used to handle fpe exceptions on the fly, like fixing
> division by zero. An other use case are breakpoints, implemented using the
> illegal opcode exception. The real time handling of the breakpoints would
> be handy for conditional breakpoints or also for stopping watchdogs and
> other tasks in time.
> 
> Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> ---
>  include/cobalt/kernel/ppd.h                   |  3 +
>  include/cobalt/kernel/thread.h                |  2 +
>  include/cobalt/signal.h                       |  2 +
>  include/cobalt/uapi/syscall.h                 |  6 ++
>  kernel/cobalt/arch/x86/Makefile               |  2 +-
>  .../arch/x86/include/asm/xenomai/thread.h     | 13 ++++
>  kernel/cobalt/arch/x86/signal_ia32.c          | 75 +++++++++++++++++++
>  kernel/cobalt/arch/x86/signal_ia64.c          | 26 +++++++
>  kernel/cobalt/dovetail/kevents.c              |  5 ++
>  kernel/cobalt/posix/process.c                 |  3 +-
>  kernel/cobalt/posix/syscall.c                 | 28 +++++++
>  kernel/cobalt/posix/syscall32.c               | 16 ++++
>  kernel/cobalt/thread.c                        | 39 ++++++++++
>  lib/cobalt/arch/x86/Makefile.am               |  2 +-
>  lib/cobalt/arch/x86/sigreturn.c               | 32 ++++++++
>  lib/cobalt/internal.h                         |  2 +
>  lib/cobalt/signal.c                           | 13 ++++
>  17 files changed, 266 insertions(+), 3 deletions(-)
>  create mode 100644 kernel/cobalt/arch/x86/signal_ia32.c
>  create mode 100644 kernel/cobalt/arch/x86/signal_ia64.c
>  create mode 100644 lib/cobalt/arch/x86/sigreturn.c
> 
> diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
> index f0079fe6e..fb2f682da 100644
> --- a/include/cobalt/kernel/ppd.h
> +++ b/include/cobalt/kernel/ppd.h
> @@ -22,6 +22,7 @@
>  #include <linux/types.h>
>  #include <linux/atomic.h>
>  #include <linux/rbtree.h>
> +#include <linux/signal.h>
>  #include <cobalt/kernel/heap.h>
> 
>  struct cobalt_umm {
> @@ -32,6 +33,8 @@ struct cobalt_umm {
> 
>  struct cobalt_ppd {
>  	struct cobalt_umm umm;
> +	void __user *sighand[_NSIG];
> +	void __user *sigrestorer;
>  	atomic_t refcnt;
>  	char *exe_path;
>  	struct rb_root fds;
> diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
> index b79cb8429..33d468419 100644
> --- a/include/cobalt/kernel/thread.h
> +++ b/include/cobalt/kernel/thread.h
> @@ -574,6 +574,8 @@ static inline void xnthread_propagate_schedparam(struct
> xnthread *curr)
>  		__xnthread_propagate_schedparam(curr);
>  }
> 
> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
> +
>  extern struct xnthread_personality xenomai_personality;
> 
>  /** @} */
> diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
> index 62694f93a..3d6540aff 100644
> --- a/include/cobalt/signal.h
> +++ b/include/cobalt/signal.h
> @@ -54,6 +54,8 @@ COBALT_DECL(int, kill(pid_t pid, int sig));
>  COBALT_DECL(int, sigqueue(pid_t pid, int sig,
>  			  const union sigval value));
> 
> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
> index 9646a0d97..6307fae7f 100644
> --- a/include/cobalt/uapi/syscall.h
> +++ b/include/cobalt/uapi/syscall.h
> @@ -137,6 +137,12 @@
>  #define sc_cobalt_recvmmsg64			114
>  #define sc_cobalt_cond_wait_prologue64		115
> 
> +/*
> + * Sigmatek specific syscalls
> + */
> +#define sc_cobalt_sigreturn			120
> +#define sc_cobalt_sigaction			121
> +
>  #define __NR_COBALT_SYSCALLS			128 /* Power of 2 */
> 
>  #endif /* !_COBALT_UAPI_SYSCALL_H */
> diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
> index 93929b645..e725afbff 100644
> --- a/kernel/cobalt/arch/x86/Makefile
> +++ b/kernel/cobalt/arch/x86/Makefile
> @@ -1,5 +1,5 @@
> 
>  obj-$(CONFIG_XENOMAI) += xenomai.o
> -xenomai-y := machine.o smi.o c1e.o
> +xenomai-y := machine.o smi.o c1e.o signal_ia32.o signal_ia64.o
> 
>  ccflags-y := -I$(srctree)/arch/x86/xenomai/include -I$(srctree)/include/xenomai
> diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> index 745c32467..4d004680b 100644
> --- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> +++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> @@ -28,5 +28,18 @@
>  #define xnarch_fault_bp_p(__nr)		((current->ptrace & PT_PTRACED)
> &&	\
>  					 ((__nr) == X86_TRAP_DB || (__nr) ==
> X86_TRAP_BP))
>  #define xnarch_fault_notify(__nr)	(!xnarch_fault_bp_p(__nr))
> +#define xnarch_fault_code(__regs)		((__regs)->orig_ax)
> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
> +			   long errcode, int *sig, struct kernel_siginfo *info);
> +
> +int xnarch_setup_rt_frame_ia32(int sig, void *handler, struct kernel_siginfo *si,
> +			  struct pt_regs *regs, void __user *restorer);
> +
> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs);
> +
> +int xnarch_setup_rt_frame_ia64(int sig, void *handler, struct kernel_siginfo *si,
> +			  struct pt_regs *regs, void __user *restorer);
> +
> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs);
> 
>  #endif /* !_COBALT_X86_ASM_THREAD_H */
> diff --git a/kernel/cobalt/arch/x86/signal_ia32.c
> b/kernel/cobalt/arch/x86/signal_ia32.c
> new file mode 100644
> index 000000000..e78c8c4d4
> --- /dev/null
> +++ b/kernel/cobalt/arch/x86/signal_ia32.c
> @@ -0,0 +1,75 @@
> +#include <linux/signal.h>
> +#include <linux/uaccess.h>
> +#include <cobalt/kernel/thread.h>
> +
> +#include <asm/sigframe.h>
> +#include <asm/sighandling.h>
> +#include <asm/fpu/signal.h>
> +
> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
> +			   long errcode, int *sig, struct kernel_siginfo *info)
> +{
> +	switch (vector) {
> +	case 0: /* divide_error */
> +		*sig = SIGFPE;
> +		info->si_signo = *sig;
> +		info->si_errno = 0;
> +		info->si_code = FPE_INTDIV;
> +		info->si_addr = (void __user *)regs->ip;
> +		return 0;
> +	case 1: /* trap_error */ {
> +		unsigned long condition;
> +		get_debugreg(condition, 6);
> +		set_debugreg(0, 7);
> +		*sig = SIGTRAP;
> +		info->si_signo = *sig;
> +		info->si_errno = errcode;
> +		info->si_code = get_si_code(condition);
> +		info->si_addr = (void __user *)regs->ip;
> +		return 0;
> +	}
> +	case 3: /* trap_error */
> +		*sig = SIGTRAP;
> +		info->si_signo = *sig;
> +		info->si_errno = errcode;
> +		info->si_code = SI_KERNEL;
> +		info->si_addr = (void __user *)regs->ip;
> +		return 0;
> +	case 6: /* invalid_op */
> +		*sig = SIGILL;
> +		info->si_signo = *sig;
> +		info->si_errno = 0;
> +		info->si_code = ILL_ILLOPN;
> +		info->si_addr = (void __user *)regs->ip;
> +		return 0;
> +	case 16: { /* coprocessor_error */
> +		*sig = SIGFPE;
> +
> +		info->si_signo = *sig;
> +		info->si_errno = 0;
> +		info->si_code = 0;
> +		info->si_addr = (void __user *)regs->ip;
> +		return 0;
> +	}
> +	default:
> +		break;
> +	}
> +
> +	return -ENOSYS;
> +}
> +
> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs)
> +{
> +	int ret;
> +
> +	ret = dovetail_restore_rt_signal_frame(regs);
> +	if (ret < 0)
> +		goto badframe;
> +
> +	return regs->ax;
> +
> +badframe:
> +	xnthread_call_mayday(xnthread_current(), SIGKILL);
> +	return -1;
> +}
> +
> diff --git a/kernel/cobalt/arch/x86/signal_ia64.c
> b/kernel/cobalt/arch/x86/signal_ia64.c
> new file mode 100644
> index 000000000..a7044db40
> --- /dev/null
> +++ b/kernel/cobalt/arch/x86/signal_ia64.c
> @@ -0,0 +1,26 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  Copyright (C) 1991, 1992  Linus Torvalds
> + *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
> + *
> + *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
> + *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
> + *  2000-2002   x86-64 support by Andi Kleen
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +
> +#include <linux/signal.h>
> +#include <linux/uaccess.h>
> +#include <cobalt/kernel/thread.h>
> +
> +#include <asm/sigframe.h>
> +#include <asm/sighandling.h>
> +#include <asm/fpu/signal.h>
> +
> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs)
> +{
> +	return dovetail_restore_rt_signal_frame(regs);
> +}
> +
> diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
> index 4da4f51b7..61417717b 100644
> --- a/kernel/cobalt/dovetail/kevents.c
> +++ b/kernel/cobalt/dovetail/kevents.c
> @@ -57,6 +57,9 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
> pt_regs *regs)
>  		xnsched_run();
>  	}
> 
> +	if (xnthread_handle_rt_signals(trapnr, regs) == 0)
> +		return;
> +
>  	/*
>  	 * If we experienced a trap on behalf of a shadow thread
>  	 * running in primary mode, move it to the Linux domain,
> @@ -88,6 +91,8 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
> pt_regs *regs)
>  		xnstat_counter_inc(&thread->stat.pf);
> 
>  	xnthread_relax(xnarch_fault_notify(trapnr), SIGDEBUG_MIGRATE_FAULT);
> +
> +	return;
>  }
> 
>  static inline int handle_setaffinity_event(struct dovetail_migration_data *d)
> diff --git a/kernel/cobalt/posix/process.c b/kernel/cobalt/posix/process.c
> index 1abc86f37..2069129cb 100644
> --- a/kernel/cobalt/posix/process.c
> +++ b/kernel/cobalt/posix/process.c
> @@ -738,9 +738,10 @@ void cobalt_unregister_debugged_thread(struct
> xnthread *thread)
>  		cobalt_resume_debugged_process(process);
>  }
> 
> +#ifdef CONFIG_SMP
> +
>  int cobalt_handle_setaffinity_event(struct task_struct *task)
>  {
> -#ifdef CONFIG_SMP
>  	struct xnthread *thread;
>  	spl_t s;
> 
> diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
> index 46c4998e4..b4bd4c587 100644
> --- a/kernel/cobalt/posix/syscall.c
> +++ b/kernel/cobalt/posix/syscall.c
> @@ -277,6 +277,34 @@ static COBALT_SYSCALL(serialdbg, current,
>  	return 0;
>  }
> 
> +static COBALT_SYSCALL(sigreturn, current, (void))
> +{
> +	struct pt_regs *regs = task_pt_regs(current);
> +
> +	if (regs->cs == __USER_CS)
> +		xnarch_rt_sigreturn_ia64(regs);
> +	if (regs->cs == __USER32_CS)
> +		xnarch_rt_sigreturn_ia32(regs);
> +
> +	return __xn_reg_rval(regs);
> +}
> +
> +static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
> +		      void __user *restorer))
> +{
> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
> +
> +	if (sig < 0 || sig >= _NSIG)
> +		return -EINVAL;
> +
> +	sys_ppd->sighand[sig] = handler;
> +
> +	if (!sys_ppd->sigrestorer)
> +		sys_ppd->sigrestorer = restorer;
> +
> +	return 0;
> +}
> +
>  static void stringify_feature_set(unsigned long fset, char *buf, int size)
>  {
>  	unsigned long feature;
> diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
> index b65a0a760..f8b21bfb2 100644
> --- a/kernel/cobalt/posix/syscall32.c
> +++ b/kernel/cobalt/posix/syscall32.c
> @@ -774,6 +774,22 @@ COBALT_SYSCALL32emu(sigqueue, conforming,
>  	return ret ?: __cobalt_sigqueue(pid, sig, &val);
>  }
> 
> +COBALT_SYSCALL32emu(sigaction, current,
> +		    (int sig, void __user *handler, void __user *restorer))
> +{
> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
> +
> +	if (sig < 0 || sig >= _NSIG)
> +		return -EINVAL;
> +
> +	sys_ppd->sighand[sig] = handler;
> +
> +	if (!sys_ppd->sigrestorer)
> +		sys_ppd->sigrestorer = restorer;
> +
> +	return 0;
> +}
> +
>  COBALT_SYSCALL32emu(monitor_wait, nonrestartable,
>  		    (struct cobalt_monitor_shadow __user *u_mon,
>  		     int event, const struct old_timespec32 __user *u_ts,
> diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
> index 41804b24f..71f97c481 100644
> --- a/kernel/cobalt/thread.c
> +++ b/kernel/cobalt/thread.c
> @@ -25,6 +25,7 @@
>  #include <linux/signal.h>
>  #include <linux/pid.h>
>  #include <linux/sched.h>
> +#include <asm/sighandling.h>
>  #include <uapi/linux/sched/types.h>
>  #include <cobalt/kernel/sched.h>
>  #include <cobalt/kernel/timer.h>
> @@ -43,6 +44,7 @@
>  #include <pipeline/inband_work.h>
>  #include <pipeline/sched.h>
>  #include <trace/events/cobalt-core.h>
> +#include "posix/process.h"
>  #include "debug.h"
> 
>  static DECLARE_WAIT_QUEUE_HEAD(join_all);
> @@ -2520,6 +2522,43 @@ int xnthread_killall(int grace, int mask)
>  }
>  EXPORT_SYMBOL_GPL(xnthread_killall);
> 
> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
> +{
> +	struct ksignal ksig;
> +
> +	unsigned int vector = trapnr;
> +	unsigned int code = xnarch_fault_code(regs);
> +	struct cobalt_ppd *sys_ppd;
> +	int sig, ret = 0;
> +	struct kernel_siginfo si;
> +
> +	code = xnarch_fault_code(regs);
> +	ret = xnarch_setup_trap_info(vector, regs, code, &sig, &si);
> +	if (ret || sig == 0)
> +		return 1;
> +
> +	sys_ppd = cobalt_ppd_get(0);
> +	if (sig >= _NSIG ||
> +	    sys_ppd->sighand[sig] == NULL ||
> +	    sys_ppd->sighand[sig] == SIG_DFL)
> +		return 1;
> +
> +	if (sys_ppd->sigrestorer == NULL)
> +		return 1;
> +
> +	ksig.sig = sig;
> +	memcpy(&ksig.info, &si, sizeof(si));
> +	ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
> +	ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
> +	ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
> +
> +	ret = dovetail_setup_rt_signal_frame(&ksig, regs);
> +	if (ret)
> +		return 1;
> +
> +	return 0;
> +}
> +
>  /* Xenomai's generic personality. */
>  struct xnthread_personality xenomai_personality = {
>  	.name = "core",
> diff --git a/lib/cobalt/arch/x86/Makefile.am b/lib/cobalt/arch/x86/Makefile.am
> index a5095be3d..14f5eff97 100644
> --- a/lib/cobalt/arch/x86/Makefile.am
> +++ b/lib/cobalt/arch/x86/Makefile.am
> @@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarch.la
> 
>  libarch_la_LDFLAGS = @XENO_LIB_LDFLAGS@
> 
> -libarch_la_SOURCES = features.c
> +libarch_la_SOURCES = features.c sigreturn.c
> 
>  libarch_la_CPPFLAGS =			\
>  	@XENO_COBALT_CFLAGS@ 		\
> diff --git a/lib/cobalt/arch/x86/sigreturn.c b/lib/cobalt/arch/x86/sigreturn.c
> new file mode 100644
> index 000000000..76292e145
> --- /dev/null
> +++ b/lib/cobalt/arch/x86/sigreturn.c
> @@ -0,0 +1,32 @@
> +#include <cobalt/uapi/syscall.h>
> +#include "internal.h"
> +
> +extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__
> ((visibility ("hidden")));
> +
> +#ifdef __x86_64__
> +#define build_restorer(syscall_number)                                         \
> +	asm(".text\n"                                                          \
> +	    "    .align 16\n"                                                  \
> +	    "__cobalt_sigreturn:\n"                                            \
> +	    "    movq $ " #syscall_number ", %rax\n"                           \
> +	    "    syscall")
> +#endif
> +
> +#ifdef __i386__
> +#define build_restorer(syscall_number)                                         \
> +	asm(".text\n"                                                          \
> +	    "    .align 16\n"                                                  \
> +	    "__cobalt_sigreturn:\n"                                            \
> +	    "    movl $ " #syscall_number ", %eax\n"                           \
> +	    "    int  $0x80")
> +#endif
> +
> +/*
> + * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
> + */
> +build_restorer(0x10000078);
> +
> +void *cobalt_get_restorer(void)
> +{
> +	return &cobalt_sigreturn;
> +}
> diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
> index acb3989f1..4782d154a 100644
> --- a/lib/cobalt/internal.h
> +++ b/lib/cobalt/internal.h
> @@ -132,4 +132,6 @@ static inline bool cobalt_features_available(unsigned int
> feat_mask)
>  	return (cobalt_features & feat_mask) == feat_mask;
>  }
> 
> +extern void *cobalt_get_restorer(void);
> +
>  #endif /* _LIB_COBALT_INTERNAL_H */
> diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
> index 40d315ebb..af174d570 100644
> --- a/lib/cobalt/signal.c
> +++ b/lib/cobalt/signal.c
> @@ -126,3 +126,16 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const
> union sigval value))
> 
>  	return 0;
>  }
> +
> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
> +{
> +	int ret;
> +
> +	ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler,
> cobalt_get_restorer());
> +	if (ret) {
> +		errno = -ret;
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-09 13:17 ` [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
@ 2023-05-12 17:38   ` Jan Kiszka
  2023-05-15  6:50     ` Johannes Kirchmair
  2023-08-09  9:50   ` Schaffner, Tobias
  1 sibling, 1 reply; 12+ messages in thread
From: Jan Kiszka @ 2023-05-12 17:38 UTC (permalink / raw)
  To: Johannes Kirchmair, xenomai, Schaffner, Tobias

On 09.05.23 15:17, Johannes Kirchmair wrote:
> Hello Jan and Tobias,
> 
> I just dropped the patches on the mailing list.
> For the dovetail functions I took a rather naive approach, using most of the frame setup code provided by Linux.
> I just tested it for 32bit and 64bit x86 Applications and it seems to work. 
> 
> I also added a tool rt_signal_hist that runs in a cycle and measures the time an exception handling takes.
> It is afterwards put into an txt file that reassembles an histogram of the timings.
> 
> Unfortunately as a 32bit application the rt_signal_hist tool does not run to completion, printing the following:
> " Xenomai/cobalt: sleeping while holding mutex
> CPU time limit exceeded"
> 
> Maybe the naive approach is not so reliable ;-/
> Hope I find the time the look into it. 
> 

I looked into the x86 signalframe helpers before and found some traces
of locking that make them incompatible - if I rember correctly. After
that, I dropped the idea of just removing the "static".

> Sorry for not putting more effort into this so fare.
> 
> The next most important step in my opinion would be to define a clean interface into dovetail for the signal frame setup and restoring.
> Actually that's the task I consider one of the harder and I am not so sure how to approach this.
> 

Exactly, and we need to involve Philippe now soon. Let me medidate over
some interface options as well. Will pick up if you don't find the time
soon.

Jan

> Best regards
> Johannes
> 
>> -----Original Message-----
>> From: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> Sent: Dienstag, 9. Mai 2023 15:14
>> To: xenomai@lists.linux.dev
>> Cc: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> Subject: [PATCH 1/3] [POC] test implementaion of rt-signals
>>
>> We implement rt signals to handle exceptions in rt stage.
>>
>> This is done using dovetail specific functions for setting up the signal
>> frame.
>>
>> This can be used to handle fpe exceptions on the fly, like fixing
>> division by zero. An other use case are breakpoints, implemented using the
>> illegal opcode exception. The real time handling of the breakpoints would
>> be handy for conditional breakpoints or also for stopping watchdogs and
>> other tasks in time.
>>
>> Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> ---
>>  include/cobalt/kernel/ppd.h                   |  3 +
>>  include/cobalt/kernel/thread.h                |  2 +
>>  include/cobalt/signal.h                       |  2 +
>>  include/cobalt/uapi/syscall.h                 |  6 ++
>>  kernel/cobalt/arch/x86/Makefile               |  2 +-
>>  .../arch/x86/include/asm/xenomai/thread.h     | 13 ++++
>>  kernel/cobalt/arch/x86/signal_ia32.c          | 75 +++++++++++++++++++
>>  kernel/cobalt/arch/x86/signal_ia64.c          | 26 +++++++
>>  kernel/cobalt/dovetail/kevents.c              |  5 ++
>>  kernel/cobalt/posix/process.c                 |  3 +-
>>  kernel/cobalt/posix/syscall.c                 | 28 +++++++
>>  kernel/cobalt/posix/syscall32.c               | 16 ++++
>>  kernel/cobalt/thread.c                        | 39 ++++++++++
>>  lib/cobalt/arch/x86/Makefile.am               |  2 +-
>>  lib/cobalt/arch/x86/sigreturn.c               | 32 ++++++++
>>  lib/cobalt/internal.h                         |  2 +
>>  lib/cobalt/signal.c                           | 13 ++++
>>  17 files changed, 266 insertions(+), 3 deletions(-)
>>  create mode 100644 kernel/cobalt/arch/x86/signal_ia32.c
>>  create mode 100644 kernel/cobalt/arch/x86/signal_ia64.c
>>  create mode 100644 lib/cobalt/arch/x86/sigreturn.c
>>
>> diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
>> index f0079fe6e..fb2f682da 100644
>> --- a/include/cobalt/kernel/ppd.h
>> +++ b/include/cobalt/kernel/ppd.h
>> @@ -22,6 +22,7 @@
>>  #include <linux/types.h>
>>  #include <linux/atomic.h>
>>  #include <linux/rbtree.h>
>> +#include <linux/signal.h>
>>  #include <cobalt/kernel/heap.h>
>>
>>  struct cobalt_umm {
>> @@ -32,6 +33,8 @@ struct cobalt_umm {
>>
>>  struct cobalt_ppd {
>>  	struct cobalt_umm umm;
>> +	void __user *sighand[_NSIG];
>> +	void __user *sigrestorer;
>>  	atomic_t refcnt;
>>  	char *exe_path;
>>  	struct rb_root fds;
>> diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
>> index b79cb8429..33d468419 100644
>> --- a/include/cobalt/kernel/thread.h
>> +++ b/include/cobalt/kernel/thread.h
>> @@ -574,6 +574,8 @@ static inline void xnthread_propagate_schedparam(struct
>> xnthread *curr)
>>  		__xnthread_propagate_schedparam(curr);
>>  }
>>
>> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
>> +
>>  extern struct xnthread_personality xenomai_personality;
>>
>>  /** @} */
>> diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
>> index 62694f93a..3d6540aff 100644
>> --- a/include/cobalt/signal.h
>> +++ b/include/cobalt/signal.h
>> @@ -54,6 +54,8 @@ COBALT_DECL(int, kill(pid_t pid, int sig));
>>  COBALT_DECL(int, sigqueue(pid_t pid, int sig,
>>  			  const union sigval value));
>>
>> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
>> +
>>  #ifdef __cplusplus
>>  }
>>  #endif
>> diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
>> index 9646a0d97..6307fae7f 100644
>> --- a/include/cobalt/uapi/syscall.h
>> +++ b/include/cobalt/uapi/syscall.h
>> @@ -137,6 +137,12 @@
>>  #define sc_cobalt_recvmmsg64			114
>>  #define sc_cobalt_cond_wait_prologue64		115
>>
>> +/*
>> + * Sigmatek specific syscalls
>> + */
>> +#define sc_cobalt_sigreturn			120
>> +#define sc_cobalt_sigaction			121
>> +
>>  #define __NR_COBALT_SYSCALLS			128 /* Power of 2 */
>>
>>  #endif /* !_COBALT_UAPI_SYSCALL_H */
>> diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
>> index 93929b645..e725afbff 100644
>> --- a/kernel/cobalt/arch/x86/Makefile
>> +++ b/kernel/cobalt/arch/x86/Makefile
>> @@ -1,5 +1,5 @@
>>
>>  obj-$(CONFIG_XENOMAI) += xenomai.o
>> -xenomai-y := machine.o smi.o c1e.o
>> +xenomai-y := machine.o smi.o c1e.o signal_ia32.o signal_ia64.o
>>
>>  ccflags-y := -I$(srctree)/arch/x86/xenomai/include -I$(srctree)/include/xenomai
>> diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> index 745c32467..4d004680b 100644
>> --- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> +++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> @@ -28,5 +28,18 @@
>>  #define xnarch_fault_bp_p(__nr)		((current->ptrace & PT_PTRACED)
>> &&	\
>>  					 ((__nr) == X86_TRAP_DB || (__nr) ==
>> X86_TRAP_BP))
>>  #define xnarch_fault_notify(__nr)	(!xnarch_fault_bp_p(__nr))
>> +#define xnarch_fault_code(__regs)		((__regs)->orig_ax)
>> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
>> +			   long errcode, int *sig, struct kernel_siginfo *info);
>> +
>> +int xnarch_setup_rt_frame_ia32(int sig, void *handler, struct kernel_siginfo *si,
>> +			  struct pt_regs *regs, void __user *restorer);
>> +
>> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs);
>> +
>> +int xnarch_setup_rt_frame_ia64(int sig, void *handler, struct kernel_siginfo *si,
>> +			  struct pt_regs *regs, void __user *restorer);
>> +
>> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs);
>>
>>  #endif /* !_COBALT_X86_ASM_THREAD_H */
>> diff --git a/kernel/cobalt/arch/x86/signal_ia32.c
>> b/kernel/cobalt/arch/x86/signal_ia32.c
>> new file mode 100644
>> index 000000000..e78c8c4d4
>> --- /dev/null
>> +++ b/kernel/cobalt/arch/x86/signal_ia32.c
>> @@ -0,0 +1,75 @@
>> +#include <linux/signal.h>
>> +#include <linux/uaccess.h>
>> +#include <cobalt/kernel/thread.h>
>> +
>> +#include <asm/sigframe.h>
>> +#include <asm/sighandling.h>
>> +#include <asm/fpu/signal.h>
>> +
>> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
>> +			   long errcode, int *sig, struct kernel_siginfo *info)
>> +{
>> +	switch (vector) {
>> +	case 0: /* divide_error */
>> +		*sig = SIGFPE;
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = FPE_INTDIV;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 1: /* trap_error */ {
>> +		unsigned long condition;
>> +		get_debugreg(condition, 6);
>> +		set_debugreg(0, 7);
>> +		*sig = SIGTRAP;
>> +		info->si_signo = *sig;
>> +		info->si_errno = errcode;
>> +		info->si_code = get_si_code(condition);
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	}
>> +	case 3: /* trap_error */
>> +		*sig = SIGTRAP;
>> +		info->si_signo = *sig;
>> +		info->si_errno = errcode;
>> +		info->si_code = SI_KERNEL;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 6: /* invalid_op */
>> +		*sig = SIGILL;
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = ILL_ILLOPN;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 16: { /* coprocessor_error */
>> +		*sig = SIGFPE;
>> +
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = 0;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	}
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return -ENOSYS;
>> +}
>> +
>> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs)
>> +{
>> +	int ret;
>> +
>> +	ret = dovetail_restore_rt_signal_frame(regs);
>> +	if (ret < 0)
>> +		goto badframe;
>> +
>> +	return regs->ax;
>> +
>> +badframe:
>> +	xnthread_call_mayday(xnthread_current(), SIGKILL);
>> +	return -1;
>> +}
>> +
>> diff --git a/kernel/cobalt/arch/x86/signal_ia64.c
>> b/kernel/cobalt/arch/x86/signal_ia64.c
>> new file mode 100644
>> index 000000000..a7044db40
>> --- /dev/null
>> +++ b/kernel/cobalt/arch/x86/signal_ia64.c
>> @@ -0,0 +1,26 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + *  Copyright (C) 1991, 1992  Linus Torvalds
>> + *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
>> + *
>> + *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
>> + *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
>> + *  2000-2002   x86-64 support by Andi Kleen
>> + */
>> +
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> +
>> +
>> +#include <linux/signal.h>
>> +#include <linux/uaccess.h>
>> +#include <cobalt/kernel/thread.h>
>> +
>> +#include <asm/sigframe.h>
>> +#include <asm/sighandling.h>
>> +#include <asm/fpu/signal.h>
>> +
>> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs)
>> +{
>> +	return dovetail_restore_rt_signal_frame(regs);
>> +}
>> +
>> diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
>> index 4da4f51b7..61417717b 100644
>> --- a/kernel/cobalt/dovetail/kevents.c
>> +++ b/kernel/cobalt/dovetail/kevents.c
>> @@ -57,6 +57,9 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
>> pt_regs *regs)
>>  		xnsched_run();
>>  	}
>>
>> +	if (xnthread_handle_rt_signals(trapnr, regs) == 0)
>> +		return;
>> +
>>  	/*
>>  	 * If we experienced a trap on behalf of a shadow thread
>>  	 * running in primary mode, move it to the Linux domain,
>> @@ -88,6 +91,8 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
>> pt_regs *regs)
>>  		xnstat_counter_inc(&thread->stat.pf);
>>
>>  	xnthread_relax(xnarch_fault_notify(trapnr), SIGDEBUG_MIGRATE_FAULT);
>> +
>> +	return;
>>  }
>>
>>  static inline int handle_setaffinity_event(struct dovetail_migration_data *d)
>> diff --git a/kernel/cobalt/posix/process.c b/kernel/cobalt/posix/process.c
>> index 1abc86f37..2069129cb 100644
>> --- a/kernel/cobalt/posix/process.c
>> +++ b/kernel/cobalt/posix/process.c
>> @@ -738,9 +738,10 @@ void cobalt_unregister_debugged_thread(struct
>> xnthread *thread)
>>  		cobalt_resume_debugged_process(process);
>>  }
>>
>> +#ifdef CONFIG_SMP
>> +
>>  int cobalt_handle_setaffinity_event(struct task_struct *task)
>>  {
>> -#ifdef CONFIG_SMP
>>  	struct xnthread *thread;
>>  	spl_t s;
>>
>> diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
>> index 46c4998e4..b4bd4c587 100644
>> --- a/kernel/cobalt/posix/syscall.c
>> +++ b/kernel/cobalt/posix/syscall.c
>> @@ -277,6 +277,34 @@ static COBALT_SYSCALL(serialdbg, current,
>>  	return 0;
>>  }
>>
>> +static COBALT_SYSCALL(sigreturn, current, (void))
>> +{
>> +	struct pt_regs *regs = task_pt_regs(current);
>> +
>> +	if (regs->cs == __USER_CS)
>> +		xnarch_rt_sigreturn_ia64(regs);
>> +	if (regs->cs == __USER32_CS)
>> +		xnarch_rt_sigreturn_ia32(regs);
>> +
>> +	return __xn_reg_rval(regs);
>> +}
>> +
>> +static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
>> +		      void __user *restorer))
>> +{
>> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
>> +
>> +	if (sig < 0 || sig >= _NSIG)
>> +		return -EINVAL;
>> +
>> +	sys_ppd->sighand[sig] = handler;
>> +
>> +	if (!sys_ppd->sigrestorer)
>> +		sys_ppd->sigrestorer = restorer;
>> +
>> +	return 0;
>> +}
>> +
>>  static void stringify_feature_set(unsigned long fset, char *buf, int size)
>>  {
>>  	unsigned long feature;
>> diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
>> index b65a0a760..f8b21bfb2 100644
>> --- a/kernel/cobalt/posix/syscall32.c
>> +++ b/kernel/cobalt/posix/syscall32.c
>> @@ -774,6 +774,22 @@ COBALT_SYSCALL32emu(sigqueue, conforming,
>>  	return ret ?: __cobalt_sigqueue(pid, sig, &val);
>>  }
>>
>> +COBALT_SYSCALL32emu(sigaction, current,
>> +		    (int sig, void __user *handler, void __user *restorer))
>> +{
>> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
>> +
>> +	if (sig < 0 || sig >= _NSIG)
>> +		return -EINVAL;
>> +
>> +	sys_ppd->sighand[sig] = handler;
>> +
>> +	if (!sys_ppd->sigrestorer)
>> +		sys_ppd->sigrestorer = restorer;
>> +
>> +	return 0;
>> +}
>> +
>>  COBALT_SYSCALL32emu(monitor_wait, nonrestartable,
>>  		    (struct cobalt_monitor_shadow __user *u_mon,
>>  		     int event, const struct old_timespec32 __user *u_ts,
>> diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
>> index 41804b24f..71f97c481 100644
>> --- a/kernel/cobalt/thread.c
>> +++ b/kernel/cobalt/thread.c
>> @@ -25,6 +25,7 @@
>>  #include <linux/signal.h>
>>  #include <linux/pid.h>
>>  #include <linux/sched.h>
>> +#include <asm/sighandling.h>
>>  #include <uapi/linux/sched/types.h>
>>  #include <cobalt/kernel/sched.h>
>>  #include <cobalt/kernel/timer.h>
>> @@ -43,6 +44,7 @@
>>  #include <pipeline/inband_work.h>
>>  #include <pipeline/sched.h>
>>  #include <trace/events/cobalt-core.h>
>> +#include "posix/process.h"
>>  #include "debug.h"
>>
>>  static DECLARE_WAIT_QUEUE_HEAD(join_all);
>> @@ -2520,6 +2522,43 @@ int xnthread_killall(int grace, int mask)
>>  }
>>  EXPORT_SYMBOL_GPL(xnthread_killall);
>>
>> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
>> +{
>> +	struct ksignal ksig;
>> +
>> +	unsigned int vector = trapnr;
>> +	unsigned int code = xnarch_fault_code(regs);
>> +	struct cobalt_ppd *sys_ppd;
>> +	int sig, ret = 0;
>> +	struct kernel_siginfo si;
>> +
>> +	code = xnarch_fault_code(regs);
>> +	ret = xnarch_setup_trap_info(vector, regs, code, &sig, &si);
>> +	if (ret || sig == 0)
>> +		return 1;
>> +
>> +	sys_ppd = cobalt_ppd_get(0);
>> +	if (sig >= _NSIG ||
>> +	    sys_ppd->sighand[sig] == NULL ||
>> +	    sys_ppd->sighand[sig] == SIG_DFL)
>> +		return 1;
>> +
>> +	if (sys_ppd->sigrestorer == NULL)
>> +		return 1;
>> +
>> +	ksig.sig = sig;
>> +	memcpy(&ksig.info, &si, sizeof(si));
>> +	ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
>> +	ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
>> +	ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
>> +
>> +	ret = dovetail_setup_rt_signal_frame(&ksig, regs);
>> +	if (ret)
>> +		return 1;
>> +
>> +	return 0;
>> +}
>> +
>>  /* Xenomai's generic personality. */
>>  struct xnthread_personality xenomai_personality = {
>>  	.name = "core",
>> diff --git a/lib/cobalt/arch/x86/Makefile.am b/lib/cobalt/arch/x86/Makefile.am
>> index a5095be3d..14f5eff97 100644
>> --- a/lib/cobalt/arch/x86/Makefile.am
>> +++ b/lib/cobalt/arch/x86/Makefile.am
>> @@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarch.la
>>
>>  libarch_la_LDFLAGS = @XENO_LIB_LDFLAGS@
>>
>> -libarch_la_SOURCES = features.c
>> +libarch_la_SOURCES = features.c sigreturn.c
>>
>>  libarch_la_CPPFLAGS =			\
>>  	@XENO_COBALT_CFLAGS@ 		\
>> diff --git a/lib/cobalt/arch/x86/sigreturn.c b/lib/cobalt/arch/x86/sigreturn.c
>> new file mode 100644
>> index 000000000..76292e145
>> --- /dev/null
>> +++ b/lib/cobalt/arch/x86/sigreturn.c
>> @@ -0,0 +1,32 @@
>> +#include <cobalt/uapi/syscall.h>
>> +#include "internal.h"
>> +
>> +extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__
>> ((visibility ("hidden")));
>> +
>> +#ifdef __x86_64__
>> +#define build_restorer(syscall_number)                                         \
>> +	asm(".text\n"                                                          \
>> +	    "    .align 16\n"                                                  \
>> +	    "__cobalt_sigreturn:\n"                                            \
>> +	    "    movq $ " #syscall_number ", %rax\n"                           \
>> +	    "    syscall")
>> +#endif
>> +
>> +#ifdef __i386__
>> +#define build_restorer(syscall_number)                                         \
>> +	asm(".text\n"                                                          \
>> +	    "    .align 16\n"                                                  \
>> +	    "__cobalt_sigreturn:\n"                                            \
>> +	    "    movl $ " #syscall_number ", %eax\n"                           \
>> +	    "    int  $0x80")
>> +#endif
>> +
>> +/*
>> + * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
>> + */
>> +build_restorer(0x10000078);
>> +
>> +void *cobalt_get_restorer(void)
>> +{
>> +	return &cobalt_sigreturn;
>> +}
>> diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
>> index acb3989f1..4782d154a 100644
>> --- a/lib/cobalt/internal.h
>> +++ b/lib/cobalt/internal.h
>> @@ -132,4 +132,6 @@ static inline bool cobalt_features_available(unsigned int
>> feat_mask)
>>  	return (cobalt_features & feat_mask) == feat_mask;
>>  }
>>
>> +extern void *cobalt_get_restorer(void);
>> +
>>  #endif /* _LIB_COBALT_INTERNAL_H */
>> diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
>> index 40d315ebb..af174d570 100644
>> --- a/lib/cobalt/signal.c
>> +++ b/lib/cobalt/signal.c
>> @@ -126,3 +126,16 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const
>> union sigval value))
>>
>>  	return 0;
>>  }
>> +
>> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
>> +{
>> +	int ret;
>> +
>> +	ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler,
>> cobalt_get_restorer());
>> +	if (ret) {
>> +		errno = -ret;
>> +		return -1;
>> +	}
>> +
>> +	return 0;
>> +}
>> --
>> 2.25.1
> 

-- 
Siemens AG, Technology
Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-12 17:38   ` Jan Kiszka
@ 2023-05-15  6:50     ` Johannes Kirchmair
  2023-05-15 10:38       ` Jan Kiszka
  0 siblings, 1 reply; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-15  6:50 UTC (permalink / raw)
  To: Jan Kiszka, xenomai, Schaffner, Tobias

> -----Original Message-----
> From: Jan Kiszka <jan.kiszka@siemens.com>
> Sent: Freitag, 12. Mai 2023 19:39
> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
> 
> CAUTION: External E-Mail !
> 
> On 09.05.23 15:17, Johannes Kirchmair wrote:
> > Hello Jan and Tobias,
> >
> > I just dropped the patches on the mailing list.
> > For the dovetail functions I took a rather naive approach, using most of the
> frame setup code provided by Linux.
> > I just tested it for 32bit and 64bit x86 Applications and it seems to work.
> >
> > I also added a tool rt_signal_hist that runs in a cycle and measures the time an
> exception handling takes.
> > It is afterwards put into an txt file that reassembles an histogram of the timings.
> >
> > Unfortunately as a 32bit application the rt_signal_hist tool does not run to
> completion, printing the following:
> > " Xenomai/cobalt: sleeping while holding mutex
> > CPU time limit exceeded"
> >
> > Maybe the naive approach is not so reliable ;-/
> > Hope I find the time the look into it.
> >
> 
> I looked into the x86 signalframe helpers before and found some traces
> of locking that make them incompatible - if I rember correctly. After
> that, I dropped the idea of just removing the "static".
Do you remember where you saw the locking in the code, was it rather obvious or hidden?
When I had a look I did not see locking in the functions I used, so I thought dropping the "static" would be fine.

Would you still try to use some of the functions Linux provides?

> 
> > Sorry for not putting more effort into this so fare.
> >
> > The next most important step in my opinion would be to define a clean interface
> into dovetail for the signal frame setup and restoring.
> > Actually that's the task I consider one of the harder and I am not so sure how to
> approach this.
> >
> 
> Exactly, and we need to involve Philippe now soon. Let me medidate over
> some interface options as well. Will pick up if you don't find the time
> soon.
At the moment, I am not event sure, what the next task would be to continue with this feature.
As I am not sure how to define the interface for dovetail, I hesitate a little bit to change the code as it is right now.

What I could do is have a look why my hist-tool breaks in the 32bit user space case.

I also could try to provide an idea for the interface, but I am not so sure if it is of good use, as my knowledge of the Kernels internal workings is still rather limited.

Best regards Johannes

> 
> Jan
> 
> > Best regards
> > Johannes
> >
> >> -----Original Message-----
> >> From: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> >> Sent: Dienstag, 9. Mai 2023 15:14
> >> To: xenomai@lists.linux.dev
> >> Cc: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> >> Subject: [PATCH 1/3] [POC] test implementaion of rt-signals
> >>
> >> We implement rt signals to handle exceptions in rt stage.
> >>
> >> This is done using dovetail specific functions for setting up the signal
> >> frame.
> >>
> >> This can be used to handle fpe exceptions on the fly, like fixing
> >> division by zero. An other use case are breakpoints, implemented using the
> >> illegal opcode exception. The real time handling of the breakpoints would
> >> be handy for conditional breakpoints or also for stopping watchdogs and
> >> other tasks in time.
> >>
> >> Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
> >> ---
> >>  include/cobalt/kernel/ppd.h                   |  3 +
> >>  include/cobalt/kernel/thread.h                |  2 +
> >>  include/cobalt/signal.h                       |  2 +
> >>  include/cobalt/uapi/syscall.h                 |  6 ++
> >>  kernel/cobalt/arch/x86/Makefile               |  2 +-
> >>  .../arch/x86/include/asm/xenomai/thread.h     | 13 ++++
> >>  kernel/cobalt/arch/x86/signal_ia32.c          | 75 +++++++++++++++++++
> >>  kernel/cobalt/arch/x86/signal_ia64.c          | 26 +++++++
> >>  kernel/cobalt/dovetail/kevents.c              |  5 ++
> >>  kernel/cobalt/posix/process.c                 |  3 +-
> >>  kernel/cobalt/posix/syscall.c                 | 28 +++++++
> >>  kernel/cobalt/posix/syscall32.c               | 16 ++++
> >>  kernel/cobalt/thread.c                        | 39 ++++++++++
> >>  lib/cobalt/arch/x86/Makefile.am               |  2 +-
> >>  lib/cobalt/arch/x86/sigreturn.c               | 32 ++++++++
> >>  lib/cobalt/internal.h                         |  2 +
> >>  lib/cobalt/signal.c                           | 13 ++++
> >>  17 files changed, 266 insertions(+), 3 deletions(-)
> >>  create mode 100644 kernel/cobalt/arch/x86/signal_ia32.c
> >>  create mode 100644 kernel/cobalt/arch/x86/signal_ia64.c
> >>  create mode 100644 lib/cobalt/arch/x86/sigreturn.c
> >>
> >> diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
> >> index f0079fe6e..fb2f682da 100644
> >> --- a/include/cobalt/kernel/ppd.h
> >> +++ b/include/cobalt/kernel/ppd.h
> >> @@ -22,6 +22,7 @@
> >>  #include <linux/types.h>
> >>  #include <linux/atomic.h>
> >>  #include <linux/rbtree.h>
> >> +#include <linux/signal.h>
> >>  #include <cobalt/kernel/heap.h>
> >>
> >>  struct cobalt_umm {
> >> @@ -32,6 +33,8 @@ struct cobalt_umm {
> >>
> >>  struct cobalt_ppd {
> >>      struct cobalt_umm umm;
> >> +    void __user *sighand[_NSIG];
> >> +    void __user *sigrestorer;
> >>      atomic_t refcnt;
> >>      char *exe_path;
> >>      struct rb_root fds;
> >> diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
> >> index b79cb8429..33d468419 100644
> >> --- a/include/cobalt/kernel/thread.h
> >> +++ b/include/cobalt/kernel/thread.h
> >> @@ -574,6 +574,8 @@ static inline void
> xnthread_propagate_schedparam(struct
> >> xnthread *curr)
> >>              __xnthread_propagate_schedparam(curr);
> >>  }
> >>
> >> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
> >> +
> >>  extern struct xnthread_personality xenomai_personality;
> >>
> >>  /** @} */
> >> diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
> >> index 62694f93a..3d6540aff 100644
> >> --- a/include/cobalt/signal.h
> >> +++ b/include/cobalt/signal.h
> >> @@ -54,6 +54,8 @@ COBALT_DECL(int, kill(pid_t pid, int sig));
> >>  COBALT_DECL(int, sigqueue(pid_t pid, int sig,
> >>                        const union sigval value));
> >>
> >> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
> >> +
> >>  #ifdef __cplusplus
> >>  }
> >>  #endif
> >> diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
> >> index 9646a0d97..6307fae7f 100644
> >> --- a/include/cobalt/uapi/syscall.h
> >> +++ b/include/cobalt/uapi/syscall.h
> >> @@ -137,6 +137,12 @@
> >>  #define sc_cobalt_recvmmsg64                        114
> >>  #define sc_cobalt_cond_wait_prologue64              115
> >>
> >> +/*
> >> + * Sigmatek specific syscalls
> >> + */
> >> +#define sc_cobalt_sigreturn                 120
> >> +#define sc_cobalt_sigaction                 121
> >> +
> >>  #define __NR_COBALT_SYSCALLS                        128 /* Power of 2 */
> >>
> >>  #endif /* !_COBALT_UAPI_SYSCALL_H */
> >> diff --git a/kernel/cobalt/arch/x86/Makefile
> b/kernel/cobalt/arch/x86/Makefile
> >> index 93929b645..e725afbff 100644
> >> --- a/kernel/cobalt/arch/x86/Makefile
> >> +++ b/kernel/cobalt/arch/x86/Makefile
> >> @@ -1,5 +1,5 @@
> >>
> >>  obj-$(CONFIG_XENOMAI) += xenomai.o
> >> -xenomai-y := machine.o smi.o c1e.o
> >> +xenomai-y := machine.o smi.o c1e.o signal_ia32.o signal_ia64.o
> >>
> >>  ccflags-y := -I$(srctree)/arch/x86/xenomai/include -
> I$(srctree)/include/xenomai
> >> diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> >> b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> >> index 745c32467..4d004680b 100644
> >> --- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> >> +++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
> >> @@ -28,5 +28,18 @@
> >>  #define xnarch_fault_bp_p(__nr)             ((current->ptrace & PT_PTRACED)
> >> &&   \
> >>                                       ((__nr) == X86_TRAP_DB || (__nr) ==
> >> X86_TRAP_BP))
> >>  #define xnarch_fault_notify(__nr)   (!xnarch_fault_bp_p(__nr))
> >> +#define xnarch_fault_code(__regs)           ((__regs)->orig_ax)
> >> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
> >> +                       long errcode, int *sig, struct kernel_siginfo *info);
> >> +
> >> +int xnarch_setup_rt_frame_ia32(int sig, void *handler, struct kernel_siginfo
> *si,
> >> +                      struct pt_regs *regs, void __user *restorer);
> >> +
> >> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs);
> >> +
> >> +int xnarch_setup_rt_frame_ia64(int sig, void *handler, struct kernel_siginfo
> *si,
> >> +                      struct pt_regs *regs, void __user *restorer);
> >> +
> >> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs);
> >>
> >>  #endif /* !_COBALT_X86_ASM_THREAD_H */
> >> diff --git a/kernel/cobalt/arch/x86/signal_ia32.c
> >> b/kernel/cobalt/arch/x86/signal_ia32.c
> >> new file mode 100644
> >> index 000000000..e78c8c4d4
> >> --- /dev/null
> >> +++ b/kernel/cobalt/arch/x86/signal_ia32.c
> >> @@ -0,0 +1,75 @@
> >> +#include <linux/signal.h>
> >> +#include <linux/uaccess.h>
> >> +#include <cobalt/kernel/thread.h>
> >> +
> >> +#include <asm/sigframe.h>
> >> +#include <asm/sighandling.h>
> >> +#include <asm/fpu/signal.h>
> >> +
> >> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
> >> +                       long errcode, int *sig, struct kernel_siginfo *info)
> >> +{
> >> +    switch (vector) {
> >> +    case 0: /* divide_error */
> >> +            *sig = SIGFPE;
> >> +            info->si_signo = *sig;
> >> +            info->si_errno = 0;
> >> +            info->si_code = FPE_INTDIV;
> >> +            info->si_addr = (void __user *)regs->ip;
> >> +            return 0;
> >> +    case 1: /* trap_error */ {
> >> +            unsigned long condition;
> >> +            get_debugreg(condition, 6);
> >> +            set_debugreg(0, 7);
> >> +            *sig = SIGTRAP;
> >> +            info->si_signo = *sig;
> >> +            info->si_errno = errcode;
> >> +            info->si_code = get_si_code(condition);
> >> +            info->si_addr = (void __user *)regs->ip;
> >> +            return 0;
> >> +    }
> >> +    case 3: /* trap_error */
> >> +            *sig = SIGTRAP;
> >> +            info->si_signo = *sig;
> >> +            info->si_errno = errcode;
> >> +            info->si_code = SI_KERNEL;
> >> +            info->si_addr = (void __user *)regs->ip;
> >> +            return 0;
> >> +    case 6: /* invalid_op */
> >> +            *sig = SIGILL;
> >> +            info->si_signo = *sig;
> >> +            info->si_errno = 0;
> >> +            info->si_code = ILL_ILLOPN;
> >> +            info->si_addr = (void __user *)regs->ip;
> >> +            return 0;
> >> +    case 16: { /* coprocessor_error */
> >> +            *sig = SIGFPE;
> >> +
> >> +            info->si_signo = *sig;
> >> +            info->si_errno = 0;
> >> +            info->si_code = 0;
> >> +            info->si_addr = (void __user *)regs->ip;
> >> +            return 0;
> >> +    }
> >> +    default:
> >> +            break;
> >> +    }
> >> +
> >> +    return -ENOSYS;
> >> +}
> >> +
> >> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs)
> >> +{
> >> +    int ret;
> >> +
> >> +    ret = dovetail_restore_rt_signal_frame(regs);
> >> +    if (ret < 0)
> >> +            goto badframe;
> >> +
> >> +    return regs->ax;
> >> +
> >> +badframe:
> >> +    xnthread_call_mayday(xnthread_current(), SIGKILL);
> >> +    return -1;
> >> +}
> >> +
> >> diff --git a/kernel/cobalt/arch/x86/signal_ia64.c
> >> b/kernel/cobalt/arch/x86/signal_ia64.c
> >> new file mode 100644
> >> index 000000000..a7044db40
> >> --- /dev/null
> >> +++ b/kernel/cobalt/arch/x86/signal_ia64.c
> >> @@ -0,0 +1,26 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + *  Copyright (C) 1991, 1992  Linus Torvalds
> >> + *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
> >> + *
> >> + *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
> >> + *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
> >> + *  2000-2002   x86-64 support by Andi Kleen
> >> + */
> >> +
> >> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >> +
> >> +
> >> +#include <linux/signal.h>
> >> +#include <linux/uaccess.h>
> >> +#include <cobalt/kernel/thread.h>
> >> +
> >> +#include <asm/sigframe.h>
> >> +#include <asm/sighandling.h>
> >> +#include <asm/fpu/signal.h>
> >> +
> >> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs)
> >> +{
> >> +    return dovetail_restore_rt_signal_frame(regs);
> >> +}
> >> +
> >> diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
> >> index 4da4f51b7..61417717b 100644
> >> --- a/kernel/cobalt/dovetail/kevents.c
> >> +++ b/kernel/cobalt/dovetail/kevents.c
> >> @@ -57,6 +57,9 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
> >> pt_regs *regs)
> >>              xnsched_run();
> >>      }
> >>
> >> +    if (xnthread_handle_rt_signals(trapnr, regs) == 0)
> >> +            return;
> >> +
> >>      /*
> >>       * If we experienced a trap on behalf of a shadow thread
> >>       * running in primary mode, move it to the Linux domain,
> >> @@ -88,6 +91,8 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
> >> pt_regs *regs)
> >>              xnstat_counter_inc(&thread->stat.pf);
> >>
> >>      xnthread_relax(xnarch_fault_notify(trapnr), SIGDEBUG_MIGRATE_FAULT);
> >> +
> >> +    return;
> >>  }
> >>
> >>  static inline int handle_setaffinity_event(struct dovetail_migration_data *d)
> >> diff --git a/kernel/cobalt/posix/process.c b/kernel/cobalt/posix/process.c
> >> index 1abc86f37..2069129cb 100644
> >> --- a/kernel/cobalt/posix/process.c
> >> +++ b/kernel/cobalt/posix/process.c
> >> @@ -738,9 +738,10 @@ void cobalt_unregister_debugged_thread(struct
> >> xnthread *thread)
> >>              cobalt_resume_debugged_process(process);
> >>  }
> >>
> >> +#ifdef CONFIG_SMP
> >> +
> >>  int cobalt_handle_setaffinity_event(struct task_struct *task)
> >>  {
> >> -#ifdef CONFIG_SMP
> >>      struct xnthread *thread;
> >>      spl_t s;
> >>
> >> diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
> >> index 46c4998e4..b4bd4c587 100644
> >> --- a/kernel/cobalt/posix/syscall.c
> >> +++ b/kernel/cobalt/posix/syscall.c
> >> @@ -277,6 +277,34 @@ static COBALT_SYSCALL(serialdbg, current,
> >>      return 0;
> >>  }
> >>
> >> +static COBALT_SYSCALL(sigreturn, current, (void))
> >> +{
> >> +    struct pt_regs *regs = task_pt_regs(current);
> >> +
> >> +    if (regs->cs == __USER_CS)
> >> +            xnarch_rt_sigreturn_ia64(regs);
> >> +    if (regs->cs == __USER32_CS)
> >> +            xnarch_rt_sigreturn_ia32(regs);
> >> +
> >> +    return __xn_reg_rval(regs);
> >> +}
> >> +
> >> +static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
> >> +                  void __user *restorer))
> >> +{
> >> +    struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
> >> +
> >> +    if (sig < 0 || sig >= _NSIG)
> >> +            return -EINVAL;
> >> +
> >> +    sys_ppd->sighand[sig] = handler;
> >> +
> >> +    if (!sys_ppd->sigrestorer)
> >> +            sys_ppd->sigrestorer = restorer;
> >> +
> >> +    return 0;
> >> +}
> >> +
> >>  static void stringify_feature_set(unsigned long fset, char *buf, int size)
> >>  {
> >>      unsigned long feature;
> >> diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
> >> index b65a0a760..f8b21bfb2 100644
> >> --- a/kernel/cobalt/posix/syscall32.c
> >> +++ b/kernel/cobalt/posix/syscall32.c
> >> @@ -774,6 +774,22 @@ COBALT_SYSCALL32emu(sigqueue, conforming,
> >>      return ret ?: __cobalt_sigqueue(pid, sig, &val);
> >>  }
> >>
> >> +COBALT_SYSCALL32emu(sigaction, current,
> >> +                (int sig, void __user *handler, void __user *restorer))
> >> +{
> >> +    struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
> >> +
> >> +    if (sig < 0 || sig >= _NSIG)
> >> +            return -EINVAL;
> >> +
> >> +    sys_ppd->sighand[sig] = handler;
> >> +
> >> +    if (!sys_ppd->sigrestorer)
> >> +            sys_ppd->sigrestorer = restorer;
> >> +
> >> +    return 0;
> >> +}
> >> +
> >>  COBALT_SYSCALL32emu(monitor_wait, nonrestartable,
> >>                  (struct cobalt_monitor_shadow __user *u_mon,
> >>                   int event, const struct old_timespec32 __user *u_ts,
> >> diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
> >> index 41804b24f..71f97c481 100644
> >> --- a/kernel/cobalt/thread.c
> >> +++ b/kernel/cobalt/thread.c
> >> @@ -25,6 +25,7 @@
> >>  #include <linux/signal.h>
> >>  #include <linux/pid.h>
> >>  #include <linux/sched.h>
> >> +#include <asm/sighandling.h>
> >>  #include <uapi/linux/sched/types.h>
> >>  #include <cobalt/kernel/sched.h>
> >>  #include <cobalt/kernel/timer.h>
> >> @@ -43,6 +44,7 @@
> >>  #include <pipeline/inband_work.h>
> >>  #include <pipeline/sched.h>
> >>  #include <trace/events/cobalt-core.h>
> >> +#include "posix/process.h"
> >>  #include "debug.h"
> >>
> >>  static DECLARE_WAIT_QUEUE_HEAD(join_all);
> >> @@ -2520,6 +2522,43 @@ int xnthread_killall(int grace, int mask)
> >>  }
> >>  EXPORT_SYMBOL_GPL(xnthread_killall);
> >>
> >> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
> >> +{
> >> +    struct ksignal ksig;
> >> +
> >> +    unsigned int vector = trapnr;
> >> +    unsigned int code = xnarch_fault_code(regs);
> >> +    struct cobalt_ppd *sys_ppd;
> >> +    int sig, ret = 0;
> >> +    struct kernel_siginfo si;
> >> +
> >> +    code = xnarch_fault_code(regs);
> >> +    ret = xnarch_setup_trap_info(vector, regs, code, &sig, &si);
> >> +    if (ret || sig == 0)
> >> +            return 1;
> >> +
> >> +    sys_ppd = cobalt_ppd_get(0);
> >> +    if (sig >= _NSIG ||
> >> +        sys_ppd->sighand[sig] == NULL ||
> >> +        sys_ppd->sighand[sig] == SIG_DFL)
> >> +            return 1;
> >> +
> >> +    if (sys_ppd->sigrestorer == NULL)
> >> +            return 1;
> >> +
> >> +    ksig.sig = sig;
> >> +    memcpy(&ksig.info, &si, sizeof(si));
> >> +    ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
> >> +    ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
> >> +    ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
> >> +
> >> +    ret = dovetail_setup_rt_signal_frame(&ksig, regs);
> >> +    if (ret)
> >> +            return 1;
> >> +
> >> +    return 0;
> >> +}
> >> +
> >>  /* Xenomai's generic personality. */
> >>  struct xnthread_personality xenomai_personality = {
> >>      .name = "core",
> >> diff --git a/lib/cobalt/arch/x86/Makefile.am b/lib/cobalt/arch/x86/Makefile.am
> >> index a5095be3d..14f5eff97 100644
> >> --- a/lib/cobalt/arch/x86/Makefile.am
> >> +++ b/lib/cobalt/arch/x86/Makefile.am
> >> @@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarch.la
> >>
> >>  libarch_la_LDFLAGS = @XENO_LIB_LDFLAGS@
> >>
> >> -libarch_la_SOURCES = features.c
> >> +libarch_la_SOURCES = features.c sigreturn.c
> >>
> >>  libarch_la_CPPFLAGS =                       \
> >>      @XENO_COBALT_CFLAGS@            \
> >> diff --git a/lib/cobalt/arch/x86/sigreturn.c b/lib/cobalt/arch/x86/sigreturn.c
> >> new file mode 100644
> >> index 000000000..76292e145
> >> --- /dev/null
> >> +++ b/lib/cobalt/arch/x86/sigreturn.c
> >> @@ -0,0 +1,32 @@
> >> +#include <cobalt/uapi/syscall.h>
> >> +#include "internal.h"
> >> +
> >> +extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__
> >> ((visibility ("hidden")));
> >> +
> >> +#ifdef __x86_64__
> >> +#define build_restorer(syscall_number)                                         \
> >> +    asm(".text\n"                                                          \
> >> +        "    .align 16\n"                                                  \
> >> +        "__cobalt_sigreturn:\n"                                            \
> >> +        "    movq $ " #syscall_number ", %rax\n"                           \
> >> +        "    syscall")
> >> +#endif
> >> +
> >> +#ifdef __i386__
> >> +#define build_restorer(syscall_number)                                         \
> >> +    asm(".text\n"                                                          \
> >> +        "    .align 16\n"                                                  \
> >> +        "__cobalt_sigreturn:\n"                                            \
> >> +        "    movl $ " #syscall_number ", %eax\n"                           \
> >> +        "    int  $0x80")
> >> +#endif
> >> +
> >> +/*
> >> + * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
> >> + */
> >> +build_restorer(0x10000078);
> >> +
> >> +void *cobalt_get_restorer(void)
> >> +{
> >> +    return &cobalt_sigreturn;
> >> +}
> >> diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
> >> index acb3989f1..4782d154a 100644
> >> --- a/lib/cobalt/internal.h
> >> +++ b/lib/cobalt/internal.h
> >> @@ -132,4 +132,6 @@ static inline bool cobalt_features_available(unsigned
> int
> >> feat_mask)
> >>      return (cobalt_features & feat_mask) == feat_mask;
> >>  }
> >>
> >> +extern void *cobalt_get_restorer(void);
> >> +
> >>  #endif /* _LIB_COBALT_INTERNAL_H */
> >> diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
> >> index 40d315ebb..af174d570 100644
> >> --- a/lib/cobalt/signal.c
> >> +++ b/lib/cobalt/signal.c
> >> @@ -126,3 +126,16 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const
> >> union sigval value))
> >>
> >>      return 0;
> >>  }
> >> +
> >> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
> >> +{
> >> +    int ret;
> >> +
> >> +    ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler,
> >> cobalt_get_restorer());
> >> +    if (ret) {
> >> +            errno = -ret;
> >> +            return -1;
> >> +    }
> >> +
> >> +    return 0;
> >> +}
> >> --
> >> 2.25.1
> >
> 
> --
> Siemens AG, Technology
> Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-15  6:50     ` Johannes Kirchmair
@ 2023-05-15 10:38       ` Jan Kiszka
  2023-05-16  6:46         ` Johannes Kirchmair
  0 siblings, 1 reply; 12+ messages in thread
From: Jan Kiszka @ 2023-05-15 10:38 UTC (permalink / raw)
  To: Johannes Kirchmair, xenomai, Schaffner, Tobias

On 15.05.23 08:50, Johannes Kirchmair wrote:
>> -----Original Message-----
>> From: Jan Kiszka <jan.kiszka@siemens.com>
>> Sent: Freitag, 12. Mai 2023 19:39
>> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
>> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
>> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
>>
>> CAUTION: External E-Mail !
>>
>> On 09.05.23 15:17, Johannes Kirchmair wrote:
>>> Hello Jan and Tobias,
>>>
>>> I just dropped the patches on the mailing list.
>>> For the dovetail functions I took a rather naive approach, using most of the
>> frame setup code provided by Linux.
>>> I just tested it for 32bit and 64bit x86 Applications and it seems to work.
>>>
>>> I also added a tool rt_signal_hist that runs in a cycle and measures the time an
>> exception handling takes.
>>> It is afterwards put into an txt file that reassembles an histogram of the timings.
>>>
>>> Unfortunately as a 32bit application the rt_signal_hist tool does not run to
>> completion, printing the following:
>>> " Xenomai/cobalt: sleeping while holding mutex
>>> CPU time limit exceeded"
>>>
>>> Maybe the naive approach is not so reliable ;-/
>>> Hope I find the time the look into it.
>>>
>>
>> I looked into the x86 signalframe helpers before and found some traces
>> of locking that make them incompatible - if I rember correctly. After
>> that, I dropped the idea of just removing the "static".
> Do you remember where you saw the locking in the code, was it rather obvious or hidden?
> When I had a look I did not see locking in the functions I used, so I thought dropping the "static" would be fine.
> 
> Would you still try to use some of the functions Linux provides?
> 

I don't recall too many details, specficially not which kernel version I
looked at. Maybe part of my concerns was that I started from
setup_rt_frame (rseq_signal_deliver), rather than x64_setup_rt_frame & Co.

I was now digging into 6.3, and one area that is sensitive is the FPU
handling. We end up in fault_in_readable, and I'm not sure yet if that
is ok. The whole FPU save/restore needs a careful check, or more, if we
are not violating the assumptions of OOB.

But did you run your code with full lock debugging enabled already? Did
you stress faulting sigframe setups/restores? That would be needed as well.

>>
>>> Sorry for not putting more effort into this so fare.
>>>
>>> The next most important step in my opinion would be to define a clean interface
>> into dovetail for the signal frame setup and restoring.
>>> Actually that's the task I consider one of the harder and I am not so sure how to
>> approach this.
>>>
>>
>> Exactly, and we need to involve Philippe now soon. Let me medidate over
>> some interface options as well. Will pick up if you don't find the time
>> soon.
> At the moment, I am not event sure, what the next task would be to continue with this feature.
> As I am not sure how to define the interface for dovetail, I hesitate a little bit to change the code as it is right now.
> 
> What I could do is have a look why my hist-tool breaks in the 32bit user space case.
> 

Agree, this needs to be understood.

> I also could try to provide an idea for the interface, but I am not so sure if it is of good use, as my knowledge of the Kernels internal workings is still rather limited.

In general, requests from the co-kernel core to switch to a signal stack
(signal setup) or restore from it (sigreturn) sounds like a reasonable
abstraction to me for now.

Jan

-- 
Siemens AG, Technology
Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-15 10:38       ` Jan Kiszka
@ 2023-05-16  6:46         ` Johannes Kirchmair
  2023-05-16  6:52           ` Jan Kiszka
  0 siblings, 1 reply; 12+ messages in thread
From: Johannes Kirchmair @ 2023-05-16  6:46 UTC (permalink / raw)
  To: Jan Kiszka, xenomai, Schaffner, Tobias

Hello, 

> -----Original Message-----
> From: Jan Kiszka <jan.kiszka@siemens.com>
> Sent: Montag, 15. Mai 2023 12:38
> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
> 
> CAUTION: External E-Mail !
> 
> On 15.05.23 08:50, Johannes Kirchmair wrote:
> >> -----Original Message-----
> >> From: Jan Kiszka <jan.kiszka@siemens.com>
> >> Sent: Freitag, 12. Mai 2023 19:39
> >> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
> >> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
> >> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
> >>
> >> CAUTION: External E-Mail !
> >>
> >> On 09.05.23 15:17, Johannes Kirchmair wrote:
> >>> Hello Jan and Tobias,
> >>>
> >>> I just dropped the patches on the mailing list.
> >>> For the dovetail functions I took a rather naive approach, using most of the
> >> frame setup code provided by Linux.
> >>> I just tested it for 32bit and 64bit x86 Applications and it seems to work.
> >>>
> >>> I also added a tool rt_signal_hist that runs in a cycle and measures the time an
> >> exception handling takes.
> >>> It is afterwards put into an txt file that reassembles an histogram of the
> timings.
> >>>
> >>> Unfortunately as a 32bit application the rt_signal_hist tool does not run to
> >> completion, printing the following:
> >>> " Xenomai/cobalt: sleeping while holding mutex
> >>> CPU time limit exceeded"
> >>>
> >>> Maybe the naive approach is not so reliable ;-/
> >>> Hope I find the time the look into it.
> >>>
> >>
> >> I looked into the x86 signalframe helpers before and found some traces
> >> of locking that make them incompatible - if I rember correctly. After
> >> that, I dropped the idea of just removing the "static".
> > Do you remember where you saw the locking in the code, was it rather obvious
> or hidden?
> > When I had a look I did not see locking in the functions I used, so I thought
> dropping the "static" would be fine.
> >
> > Would you still try to use some of the functions Linux provides?
> >
> 
> I don't recall too many details, specficially not which kernel version I
> looked at. Maybe part of my concerns was that I started from
> setup_rt_frame (rseq_signal_deliver), rather than x64_setup_rt_frame & Co.
> 
> I was now digging into 6.3, and one area that is sensitive is the FPU
> handling. We end up in fault_in_readable, and I'm not sure yet if that
> is ok. The whole FPU save/restore needs a careful check, or more, if we
> are not violating the assumptions of OOB.
> 
> But did you run your code with full lock debugging enabled already? Did
> you stress faulting sigframe setups/restores? That would be needed as well.

Yes, thought about activating debugging in kernel, yesterday. Resulting in the following kernel output:
[   83.338288] ------------[ cut here ]------------
[   83.338292] WARNING: CPU: 3 PID: 268 at mm/memory.c:5640 __might_fault+0x28/0x30
[   83.338299] Modules linked in:
[   83.338301] CPU: 3 PID: 268 Comm: signal_test_tas Tainted: G        W          6.3.0+ #7
[   83.338304] Hardware name: Default string Default string/Default string, BIOS 5.19 04/28/2022
[   83.338305] IRQ stage: Xenomai
[   83.338306] RIP: 0010:__might_fault+0x28/0x30
[   83.338308] Code: 90 90 f3 0f 1e fa 0f 1f 44 00 00 55 65 8b 05 57 11 24 6a 48 89 e5 a9 00 00 00 02 75 06 5d c3 cc cc cc cc 9c 58 f6 c4 02 75 f3 <0f> 0b 5d c3 cc cc cc cc 90 90 90 90 90 90 90 90 90 90 90 90 90 90
[   83.338311] RSP: 0000:ffffafbc417d3cb8 EFLAGS: 00010046
[   83.338313] RAX: 0000000000000006 RBX: 00000000df53adbc RCX: ffffafbc417d3d68
[   83.338314] RDX: 00000000000002b4 RSI: 0000000000000060 RDI: ffffffff9782ead0
[   83.338315] RBP: ffffafbc417d3cb8 R08: ffffafbc417d3e48 R09: 0000000000000001
[   83.338316] R10: 0000000000000001 R11: 0000000000000000 R12: 00000000df53af40
[   83.338317] R13: ffffafbc417d3db8 R14: 0000000002000000 R15: 0000000000000000
[   83.338318] FS:  0000000000000000(0000) GS:ffff966e2e000000(0063) knlGS:00000000df53bb40
[   83.338320] CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
[   83.338321] CR2: 00000000f7ee7080 CR3: 0000000006550000 CR4: 0000000000350ee0
[   83.338323] Call Trace:
[   83.338325]  <TASK>
[   83.338328]  copy_fpstate_to_sigframe+0xaa/0x410
[   83.338335]  get_sigframe+0xdc/0x2e0
[   83.338339]  ia32_setup_rt_frame+0x67/0x2f0
[   83.338343]  dovetail_setup_rt_signal_frame+0x43/0x50
[   83.338346]  xnthread_handle_rt_signals+0xf2/0x130
[   83.338349]  ? handle_head_syscall+0x179/0x550
[   83.338352]  ? __pfx_CoBaLt_sigaction+0x10/0x10
[   83.338355]  ? handle_head_syscall+0x179/0x550
[   83.338357]  ? __pfx_CoBaLt_sigaction+0x10/0x10
[   83.338359]  handle_oob_trap_entry+0x1b6/0x3c0
[   83.338362]  ? syscall_enter_from_user_mode_work+0x31/0xb0
[   83.338366]  __oob_trap_notify+0x2f/0x40
[   83.338368]  exc_invalid_op+0xb7/0x110
[   83.338371]  asm_exc_invalid_op+0x1f/0x30
[   83.338374] RIP: 0023:0x5659868a
[   83.338376] Code: Unable to access opcode bytes at 0x56598660.
[   83.338377] RSP: 002b:00000000df53b1c0 EFLAGS: 00010246
[   83.338378] RAX: 00000000f453ff4d RBX: 000000005659b000 RCX: 0000000000000000
[   83.338379] RDX: 0000000000000012 RSI: 00000000f453ff4d RDI: 00000000f7ed3ac8
[   83.338380] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
[   83.338381] R10: 0000000000000000 R11: 0000000000000296 R12: 0000000000000000
[   83.338382] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[   83.338386]  </TASK>
[   83.338387] irq event stamp: 0
[   83.338388] hardirqs last  enabled at (0): [<0000000000000000>] 0x0
[   83.338389] hardirqs last disabled at (0): [<ffffffff95cb68eb>] copy_process+0x7fb/0x21b0
[   83.338393] softirqs last  enabled at (0): [<ffffffff95cb68ef>] copy_process+0x7ff/0x21b0
[   83.338395] softirqs last disabled at (0): [<0000000000000000>] 0x0
[   83.338396] ---[ end trace 0000000000000000 ]---

Do you think, this is related to the message I get on execution.

Other question: By "stress faulting" you mean running tests while generating a lot of cpu load?

  Johannes
> 
> >>
> >>> Sorry for not putting more effort into this so fare.
> >>>
> >>> The next most important step in my opinion would be to define a clean
> interface
> >> into dovetail for the signal frame setup and restoring.
> >>> Actually that's the task I consider one of the harder and I am not so sure how
> to
> >> approach this.
> >>>
> >>
> >> Exactly, and we need to involve Philippe now soon. Let me medidate over
> >> some interface options as well. Will pick up if you don't find the time
> >> soon.
> > At the moment, I am not event sure, what the next task would be to continue
> with this feature.
> > As I am not sure how to define the interface for dovetail, I hesitate a little bit to
> change the code as it is right now.
> >
> > What I could do is have a look why my hist-tool breaks in the 32bit user space
> case.
> >
> 
> Agree, this needs to be understood.
> 
> > I also could try to provide an idea for the interface, but I am not so sure if it is of
> good use, as my knowledge of the Kernels internal workings is still rather limited.
> 
> In general, requests from the co-kernel core to switch to a signal stack
> (signal setup) or restore from it (sigreturn) sounds like a reasonable
> abstraction to me for now.
> 
> Jan
> 
> --
> Siemens AG, Technology
> Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-16  6:46         ` Johannes Kirchmair
@ 2023-05-16  6:52           ` Jan Kiszka
  0 siblings, 0 replies; 12+ messages in thread
From: Jan Kiszka @ 2023-05-16  6:52 UTC (permalink / raw)
  To: Johannes Kirchmair, xenomai, Schaffner, Tobias

On 16.05.23 08:46, Johannes Kirchmair wrote:
> Hello, 
> 
>> -----Original Message-----
>> From: Jan Kiszka <jan.kiszka@siemens.com>
>> Sent: Montag, 15. Mai 2023 12:38
>> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
>> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
>> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
>>
>> CAUTION: External E-Mail !
>>
>> On 15.05.23 08:50, Johannes Kirchmair wrote:
>>>> -----Original Message-----
>>>> From: Jan Kiszka <jan.kiszka@siemens.com>
>>>> Sent: Freitag, 12. Mai 2023 19:39
>>>> To: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>;
>>>> xenomai@lists.linux.dev; Schaffner, Tobias <tobias.schaffner@siemens.com>
>>>> Subject: Re: [PATCH 1/3] [POC] test implementaion of rt-signals
>>>>
>>>> CAUTION: External E-Mail !
>>>>
>>>> On 09.05.23 15:17, Johannes Kirchmair wrote:
>>>>> Hello Jan and Tobias,
>>>>>
>>>>> I just dropped the patches on the mailing list.
>>>>> For the dovetail functions I took a rather naive approach, using most of the
>>>> frame setup code provided by Linux.
>>>>> I just tested it for 32bit and 64bit x86 Applications and it seems to work.
>>>>>
>>>>> I also added a tool rt_signal_hist that runs in a cycle and measures the time an
>>>> exception handling takes.
>>>>> It is afterwards put into an txt file that reassembles an histogram of the
>> timings.
>>>>>
>>>>> Unfortunately as a 32bit application the rt_signal_hist tool does not run to
>>>> completion, printing the following:
>>>>> " Xenomai/cobalt: sleeping while holding mutex
>>>>> CPU time limit exceeded"
>>>>>
>>>>> Maybe the naive approach is not so reliable ;-/
>>>>> Hope I find the time the look into it.
>>>>>
>>>>
>>>> I looked into the x86 signalframe helpers before and found some traces
>>>> of locking that make them incompatible - if I rember correctly. After
>>>> that, I dropped the idea of just removing the "static".
>>> Do you remember where you saw the locking in the code, was it rather obvious
>> or hidden?
>>> When I had a look I did not see locking in the functions I used, so I thought
>> dropping the "static" would be fine.
>>>
>>> Would you still try to use some of the functions Linux provides?
>>>
>>
>> I don't recall too many details, specficially not which kernel version I
>> looked at. Maybe part of my concerns was that I started from
>> setup_rt_frame (rseq_signal_deliver), rather than x64_setup_rt_frame & Co.
>>
>> I was now digging into 6.3, and one area that is sensitive is the FPU
>> handling. We end up in fault_in_readable, and I'm not sure yet if that
>> is ok. The whole FPU save/restore needs a careful check, or more, if we
>> are not violating the assumptions of OOB.
>>
>> But did you run your code with full lock debugging enabled already? Did
>> you stress faulting sigframe setups/restores? That would be needed as well.
> 
> Yes, thought about activating debugging in kernel, yesterday. Resulting in the following kernel output:
> [   83.338288] ------------[ cut here ]------------
> [   83.338292] WARNING: CPU: 3 PID: 268 at mm/memory.c:5640 __might_fault+0x28/0x30
> [   83.338299] Modules linked in:
> [   83.338301] CPU: 3 PID: 268 Comm: signal_test_tas Tainted: G        W          6.3.0+ #7
> [   83.338304] Hardware name: Default string Default string/Default string, BIOS 5.19 04/28/2022
> [   83.338305] IRQ stage: Xenomai
> [   83.338306] RIP: 0010:__might_fault+0x28/0x30
> [   83.338308] Code: 90 90 f3 0f 1e fa 0f 1f 44 00 00 55 65 8b 05 57 11 24 6a 48 89 e5 a9 00 00 00 02 75 06 5d c3 cc cc cc cc 9c 58 f6 c4 02 75 f3 <0f> 0b 5d c3 cc cc cc cc 90 90 90 90 90 90 90 90 90 90 90 90 90 90
> [   83.338311] RSP: 0000:ffffafbc417d3cb8 EFLAGS: 00010046
> [   83.338313] RAX: 0000000000000006 RBX: 00000000df53adbc RCX: ffffafbc417d3d68
> [   83.338314] RDX: 00000000000002b4 RSI: 0000000000000060 RDI: ffffffff9782ead0
> [   83.338315] RBP: ffffafbc417d3cb8 R08: ffffafbc417d3e48 R09: 0000000000000001
> [   83.338316] R10: 0000000000000001 R11: 0000000000000000 R12: 00000000df53af40
> [   83.338317] R13: ffffafbc417d3db8 R14: 0000000002000000 R15: 0000000000000000
> [   83.338318] FS:  0000000000000000(0000) GS:ffff966e2e000000(0063) knlGS:00000000df53bb40
> [   83.338320] CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
> [   83.338321] CR2: 00000000f7ee7080 CR3: 0000000006550000 CR4: 0000000000350ee0
> [   83.338323] Call Trace:
> [   83.338325]  <TASK>
> [   83.338328]  copy_fpstate_to_sigframe+0xaa/0x410
> [   83.338335]  get_sigframe+0xdc/0x2e0
> [   83.338339]  ia32_setup_rt_frame+0x67/0x2f0
> [   83.338343]  dovetail_setup_rt_signal_frame+0x43/0x50
> [   83.338346]  xnthread_handle_rt_signals+0xf2/0x130
> [   83.338349]  ? handle_head_syscall+0x179/0x550
> [   83.338352]  ? __pfx_CoBaLt_sigaction+0x10/0x10
> [   83.338355]  ? handle_head_syscall+0x179/0x550
> [   83.338357]  ? __pfx_CoBaLt_sigaction+0x10/0x10
> [   83.338359]  handle_oob_trap_entry+0x1b6/0x3c0
> [   83.338362]  ? syscall_enter_from_user_mode_work+0x31/0xb0
> [   83.338366]  __oob_trap_notify+0x2f/0x40
> [   83.338368]  exc_invalid_op+0xb7/0x110
> [   83.338371]  asm_exc_invalid_op+0x1f/0x30
> [   83.338374] RIP: 0023:0x5659868a
> [   83.338376] Code: Unable to access opcode bytes at 0x56598660.
> [   83.338377] RSP: 002b:00000000df53b1c0 EFLAGS: 00010246
> [   83.338378] RAX: 00000000f453ff4d RBX: 000000005659b000 RCX: 0000000000000000
> [   83.338379] RDX: 0000000000000012 RSI: 00000000f453ff4d RDI: 00000000f7ed3ac8
> [   83.338380] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
> [   83.338381] R10: 0000000000000000 R11: 0000000000000296 R12: 0000000000000000
> [   83.338382] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
> [   83.338386]  </TASK>
> [   83.338387] irq event stamp: 0
> [   83.338388] hardirqs last  enabled at (0): [<0000000000000000>] 0x0
> [   83.338389] hardirqs last disabled at (0): [<ffffffff95cb68eb>] copy_process+0x7fb/0x21b0
> [   83.338393] softirqs last  enabled at (0): [<ffffffff95cb68ef>] copy_process+0x7ff/0x21b0
> [   83.338395] softirqs last disabled at (0): [<0000000000000000>] 0x0
> [   83.338396] ---[ end trace 0000000000000000 ]---
> 
> Do you think, this is related to the message I get on execution.

I don't think so unless we actually ran into a fault in your 32-bit case.

This one here is unhappy that a fault might be taken with hard IRQs off,
see __might_fault:

 #if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
 void __might_fault(const char *file, int line)
 {
+       /*
+        * When running over the oob stage (e.g. some co-kernel's own
+        * thread), we should only make sure to run with hw IRQs
+        * enabled before accessing the memory.
+        */
+       if (running_oob()) {
+               WARN_ON_ONCE(hard_irqs_disabled());
+               return;
+       }

> 
> Other question: By "stress faulting" you mean running tests while generating a lot of cpu load?

No, I meant constructing fault-causing sigframes or stacks so that we
actually take faults. Normally, the involved memory should all be
present and locked into the process.

Jan

-- 
Siemens AG, Technology
Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] [POC] test implementaion of rt-signals
  2023-05-09 13:17 ` [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
  2023-05-12 17:38   ` Jan Kiszka
@ 2023-08-09  9:50   ` Schaffner, Tobias
  1 sibling, 0 replies; 12+ messages in thread
From: Schaffner, Tobias @ 2023-08-09  9:50 UTC (permalink / raw)
  To: johannes.kirchmair, xenomai, Kiszka, Jan

Hi Johannes,

On 09.05.23 15:17, Johannes Kirchmair wrote:
> Hello Jan and Tobias,
> 
> I just dropped the patches on the mailing list.
> For the dovetail functions I took a rather naive approach, using most of the frame setup code provided by Linux.
> I just tested it for 32bit and 64bit x86 Applications and it seems to work.
> 
> I also added a tool rt_signal_hist that runs in a cycle and measures the time an exception handling takes.
> It is afterwards put into an txt file that reassembles an histogram of the timings.
> 
> Unfortunately as a 32bit application the rt_signal_hist tool does not run to completion, printing the following:
> " Xenomai/cobalt: sleeping while holding mutex
> CPU time limit exceeded"

I finally had some time to look at it again.

There is a problem in the dovetail patch you send.

In dovetail_restore_32_rt_signal_frame the ax register is returned. This 
is a long unsigned int that is returned as an int. When it becomes 
negative every now and then, it is interpreted as an error.

The dovetail_restore_64_rt_signal_frame function has the same issue, but 
the return value is ignored for x64.

As you already noticed:
The xnarch_rt_sigreturn_ia32 reacts with a 
xnthread_call_mayday(xnthread_current(), SIGKILL);

SIGKILL may not be used in this context. It is interpreted as a 
sigdebug_reason which leads to the wrong SIGDEBUG_MUTEX_SLEEP signal and 
the corresponding "Xenomai/cobalt: sleeping while holding mutex" message.


All the best,
Tobias

> Maybe the naive approach is not so reliable ;-/
> Hope I find the time the look into it.
> 
> Sorry for not putting more effort into this so fare.
> 
> The next most important step in my opinion would be to define a clean interface into dovetail for the signal frame setup and restoring.
> Actually that's the task I consider one of the harder and I am not so sure how to approach this.
> 
> Best regards
> Johannes
> 
>> -----Original Message-----
>> From: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> Sent: Dienstag, 9. Mai 2023 15:14
>> To: xenomai@lists.linux.dev
>> Cc: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> Subject: [PATCH 1/3] [POC] test implementaion of rt-signals
>>
>> We implement rt signals to handle exceptions in rt stage.
>>
>> This is done using dovetail specific functions for setting up the signal
>> frame.
>>
>> This can be used to handle fpe exceptions on the fly, like fixing
>> division by zero. An other use case are breakpoints, implemented using the
>> illegal opcode exception. The real time handling of the breakpoints would
>> be handy for conditional breakpoints or also for stopping watchdogs and
>> other tasks in time.
>>
>> Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
>> ---
>>   include/cobalt/kernel/ppd.h                   |  3 +
>>   include/cobalt/kernel/thread.h                |  2 +
>>   include/cobalt/signal.h                       |  2 +
>>   include/cobalt/uapi/syscall.h                 |  6 ++
>>   kernel/cobalt/arch/x86/Makefile               |  2 +-
>>   .../arch/x86/include/asm/xenomai/thread.h     | 13 ++++
>>   kernel/cobalt/arch/x86/signal_ia32.c          | 75 +++++++++++++++++++
>>   kernel/cobalt/arch/x86/signal_ia64.c          | 26 +++++++
>>   kernel/cobalt/dovetail/kevents.c              |  5 ++
>>   kernel/cobalt/posix/process.c                 |  3 +-
>>   kernel/cobalt/posix/syscall.c                 | 28 +++++++
>>   kernel/cobalt/posix/syscall32.c               | 16 ++++
>>   kernel/cobalt/thread.c                        | 39 ++++++++++
>>   lib/cobalt/arch/x86/Makefile.am               |  2 +-
>>   lib/cobalt/arch/x86/sigreturn.c               | 32 ++++++++
>>   lib/cobalt/internal.h                         |  2 +
>>   lib/cobalt/signal.c                           | 13 ++++
>>   17 files changed, 266 insertions(+), 3 deletions(-)
>>   create mode 100644 kernel/cobalt/arch/x86/signal_ia32.c
>>   create mode 100644 kernel/cobalt/arch/x86/signal_ia64.c
>>   create mode 100644 lib/cobalt/arch/x86/sigreturn.c
>>
>> diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
>> index f0079fe6e..fb2f682da 100644
>> --- a/include/cobalt/kernel/ppd.h
>> +++ b/include/cobalt/kernel/ppd.h
>> @@ -22,6 +22,7 @@
>>   #include <linux/types.h>
>>   #include <linux/atomic.h>
>>   #include <linux/rbtree.h>
>> +#include <linux/signal.h>
>>   #include <cobalt/kernel/heap.h>
>>
>>   struct cobalt_umm {
>> @@ -32,6 +33,8 @@ struct cobalt_umm {
>>
>>   struct cobalt_ppd {
>>   	struct cobalt_umm umm;
>> +	void __user *sighand[_NSIG];
>> +	void __user *sigrestorer;
>>   	atomic_t refcnt;
>>   	char *exe_path;
>>   	struct rb_root fds;
>> diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h
>> index b79cb8429..33d468419 100644
>> --- a/include/cobalt/kernel/thread.h
>> +++ b/include/cobalt/kernel/thread.h
>> @@ -574,6 +574,8 @@ static inline void xnthread_propagate_schedparam(struct
>> xnthread *curr)
>>   		__xnthread_propagate_schedparam(curr);
>>   }
>>
>> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs);
>> +
>>   extern struct xnthread_personality xenomai_personality;
>>
>>   /** @} */
>> diff --git a/include/cobalt/signal.h b/include/cobalt/signal.h
>> index 62694f93a..3d6540aff 100644
>> --- a/include/cobalt/signal.h
>> +++ b/include/cobalt/signal.h
>> @@ -54,6 +54,8 @@ COBALT_DECL(int, kill(pid_t pid, int sig));
>>   COBALT_DECL(int, sigqueue(pid_t pid, int sig,
>>   			  const union sigval value));
>>
>> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *));
>> +
>>   #ifdef __cplusplus
>>   }
>>   #endif
>> diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
>> index 9646a0d97..6307fae7f 100644
>> --- a/include/cobalt/uapi/syscall.h
>> +++ b/include/cobalt/uapi/syscall.h
>> @@ -137,6 +137,12 @@
>>   #define sc_cobalt_recvmmsg64			114
>>   #define sc_cobalt_cond_wait_prologue64		115
>>
>> +/*
>> + * Sigmatek specific syscalls
>> + */
>> +#define sc_cobalt_sigreturn			120
>> +#define sc_cobalt_sigaction			121
>> +
>>   #define __NR_COBALT_SYSCALLS			128 /* Power of 2 */
>>
>>   #endif /* !_COBALT_UAPI_SYSCALL_H */
>> diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
>> index 93929b645..e725afbff 100644
>> --- a/kernel/cobalt/arch/x86/Makefile
>> +++ b/kernel/cobalt/arch/x86/Makefile
>> @@ -1,5 +1,5 @@
>>
>>   obj-$(CONFIG_XENOMAI) += xenomai.o
>> -xenomai-y := machine.o smi.o c1e.o
>> +xenomai-y := machine.o smi.o c1e.o signal_ia32.o signal_ia64.o
>>
>>   ccflags-y := -I$(srctree)/arch/x86/xenomai/include -I$(srctree)/include/xenomai
>> diff --git a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> index 745c32467..4d004680b 100644
>> --- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> +++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
>> @@ -28,5 +28,18 @@
>>   #define xnarch_fault_bp_p(__nr)		((current->ptrace & PT_PTRACED)
>> &&	\
>>   					 ((__nr) == X86_TRAP_DB || (__nr) ==
>> X86_TRAP_BP))
>>   #define xnarch_fault_notify(__nr)	(!xnarch_fault_bp_p(__nr))
>> +#define xnarch_fault_code(__regs)		((__regs)->orig_ax)
>> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
>> +			   long errcode, int *sig, struct kernel_siginfo *info);
>> +
>> +int xnarch_setup_rt_frame_ia32(int sig, void *handler, struct kernel_siginfo *si,
>> +			  struct pt_regs *regs, void __user *restorer);
>> +
>> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs);
>> +
>> +int xnarch_setup_rt_frame_ia64(int sig, void *handler, struct kernel_siginfo *si,
>> +			  struct pt_regs *regs, void __user *restorer);
>> +
>> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs);
>>
>>   #endif /* !_COBALT_X86_ASM_THREAD_H */
>> diff --git a/kernel/cobalt/arch/x86/signal_ia32.c
>> b/kernel/cobalt/arch/x86/signal_ia32.c
>> new file mode 100644
>> index 000000000..e78c8c4d4
>> --- /dev/null
>> +++ b/kernel/cobalt/arch/x86/signal_ia32.c
>> @@ -0,0 +1,75 @@
>> +#include <linux/signal.h>
>> +#include <linux/uaccess.h>
>> +#include <cobalt/kernel/thread.h>
>> +
>> +#include <asm/sigframe.h>
>> +#include <asm/sighandling.h>
>> +#include <asm/fpu/signal.h>
>> +
>> +int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
>> +			   long errcode, int *sig, struct kernel_siginfo *info)
>> +{
>> +	switch (vector) {
>> +	case 0: /* divide_error */
>> +		*sig = SIGFPE;
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = FPE_INTDIV;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 1: /* trap_error */ {
>> +		unsigned long condition;
>> +		get_debugreg(condition, 6);
>> +		set_debugreg(0, 7);
>> +		*sig = SIGTRAP;
>> +		info->si_signo = *sig;
>> +		info->si_errno = errcode;
>> +		info->si_code = get_si_code(condition);
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	}
>> +	case 3: /* trap_error */
>> +		*sig = SIGTRAP;
>> +		info->si_signo = *sig;
>> +		info->si_errno = errcode;
>> +		info->si_code = SI_KERNEL;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 6: /* invalid_op */
>> +		*sig = SIGILL;
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = ILL_ILLOPN;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	case 16: { /* coprocessor_error */
>> +		*sig = SIGFPE;
>> +
>> +		info->si_signo = *sig;
>> +		info->si_errno = 0;
>> +		info->si_code = 0;
>> +		info->si_addr = (void __user *)regs->ip;
>> +		return 0;
>> +	}
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return -ENOSYS;
>> +}
>> +
>> +int xnarch_rt_sigreturn_ia32(struct pt_regs *regs)
>> +{
>> +	int ret;
>> +
>> +	ret = dovetail_restore_rt_signal_frame(regs);
>> +	if (ret < 0)
>> +		goto badframe;
>> +
>> +	return regs->ax;
>> +
>> +badframe:
>> +	xnthread_call_mayday(xnthread_current(), SIGKILL);
>> +	return -1;
>> +}
>> +
>> diff --git a/kernel/cobalt/arch/x86/signal_ia64.c
>> b/kernel/cobalt/arch/x86/signal_ia64.c
>> new file mode 100644
>> index 000000000..a7044db40
>> --- /dev/null
>> +++ b/kernel/cobalt/arch/x86/signal_ia64.c
>> @@ -0,0 +1,26 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + *  Copyright (C) 1991, 1992  Linus Torvalds
>> + *  Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
>> + *
>> + *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
>> + *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
>> + *  2000-2002   x86-64 support by Andi Kleen
>> + */
>> +
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> +
>> +
>> +#include <linux/signal.h>
>> +#include <linux/uaccess.h>
>> +#include <cobalt/kernel/thread.h>
>> +
>> +#include <asm/sigframe.h>
>> +#include <asm/sighandling.h>
>> +#include <asm/fpu/signal.h>
>> +
>> +int xnarch_rt_sigreturn_ia64(struct pt_regs *regs)
>> +{
>> +	return dovetail_restore_rt_signal_frame(regs);
>> +}
>> +
>> diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
>> index 4da4f51b7..61417717b 100644
>> --- a/kernel/cobalt/dovetail/kevents.c
>> +++ b/kernel/cobalt/dovetail/kevents.c
>> @@ -57,6 +57,9 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
>> pt_regs *regs)
>>   		xnsched_run();
>>   	}
>>
>> +	if (xnthread_handle_rt_signals(trapnr, regs) == 0)
>> +		return;
>> +
>>   	/*
>>   	 * If we experienced a trap on behalf of a shadow thread
>>   	 * running in primary mode, move it to the Linux domain,
>> @@ -88,6 +91,8 @@ void handle_oob_trap_entry(unsigned int trapnr, struct
>> pt_regs *regs)
>>   		xnstat_counter_inc(&thread->stat.pf);
>>
>>   	xnthread_relax(xnarch_fault_notify(trapnr), SIGDEBUG_MIGRATE_FAULT);
>> +
>> +	return;
>>   }
>>
>>   static inline int handle_setaffinity_event(struct dovetail_migration_data *d)
>> diff --git a/kernel/cobalt/posix/process.c b/kernel/cobalt/posix/process.c
>> index 1abc86f37..2069129cb 100644
>> --- a/kernel/cobalt/posix/process.c
>> +++ b/kernel/cobalt/posix/process.c
>> @@ -738,9 +738,10 @@ void cobalt_unregister_debugged_thread(struct
>> xnthread *thread)
>>   		cobalt_resume_debugged_process(process);
>>   }
>>
>> +#ifdef CONFIG_SMP
>> +
>>   int cobalt_handle_setaffinity_event(struct task_struct *task)
>>   {
>> -#ifdef CONFIG_SMP
>>   	struct xnthread *thread;
>>   	spl_t s;
>>
>> diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
>> index 46c4998e4..b4bd4c587 100644
>> --- a/kernel/cobalt/posix/syscall.c
>> +++ b/kernel/cobalt/posix/syscall.c
>> @@ -277,6 +277,34 @@ static COBALT_SYSCALL(serialdbg, current,
>>   	return 0;
>>   }
>>
>> +static COBALT_SYSCALL(sigreturn, current, (void))
>> +{
>> +	struct pt_regs *regs = task_pt_regs(current);
>> +
>> +	if (regs->cs == __USER_CS)
>> +		xnarch_rt_sigreturn_ia64(regs);
>> +	if (regs->cs == __USER32_CS)
>> +		xnarch_rt_sigreturn_ia32(regs);
>> +
>> +	return __xn_reg_rval(regs);
>> +}
>> +
>> +static COBALT_SYSCALL(sigaction, current, (int sig, void __user *handler,
>> +		      void __user *restorer))
>> +{
>> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
>> +
>> +	if (sig < 0 || sig >= _NSIG)
>> +		return -EINVAL;
>> +
>> +	sys_ppd->sighand[sig] = handler;
>> +
>> +	if (!sys_ppd->sigrestorer)
>> +		sys_ppd->sigrestorer = restorer;
>> +
>> +	return 0;
>> +}
>> +
>>   static void stringify_feature_set(unsigned long fset, char *buf, int size)
>>   {
>>   	unsigned long feature;
>> diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
>> index b65a0a760..f8b21bfb2 100644
>> --- a/kernel/cobalt/posix/syscall32.c
>> +++ b/kernel/cobalt/posix/syscall32.c
>> @@ -774,6 +774,22 @@ COBALT_SYSCALL32emu(sigqueue, conforming,
>>   	return ret ?: __cobalt_sigqueue(pid, sig, &val);
>>   }
>>
>> +COBALT_SYSCALL32emu(sigaction, current,
>> +		    (int sig, void __user *handler, void __user *restorer))
>> +{
>> +	struct cobalt_ppd *sys_ppd = cobalt_ppd_get(0);
>> +
>> +	if (sig < 0 || sig >= _NSIG)
>> +		return -EINVAL;
>> +
>> +	sys_ppd->sighand[sig] = handler;
>> +
>> +	if (!sys_ppd->sigrestorer)
>> +		sys_ppd->sigrestorer = restorer;
>> +
>> +	return 0;
>> +}
>> +
>>   COBALT_SYSCALL32emu(monitor_wait, nonrestartable,
>>   		    (struct cobalt_monitor_shadow __user *u_mon,
>>   		     int event, const struct old_timespec32 __user *u_ts,
>> diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
>> index 41804b24f..71f97c481 100644
>> --- a/kernel/cobalt/thread.c
>> +++ b/kernel/cobalt/thread.c
>> @@ -25,6 +25,7 @@
>>   #include <linux/signal.h>
>>   #include <linux/pid.h>
>>   #include <linux/sched.h>
>> +#include <asm/sighandling.h>
>>   #include <uapi/linux/sched/types.h>
>>   #include <cobalt/kernel/sched.h>
>>   #include <cobalt/kernel/timer.h>
>> @@ -43,6 +44,7 @@
>>   #include <pipeline/inband_work.h>
>>   #include <pipeline/sched.h>
>>   #include <trace/events/cobalt-core.h>
>> +#include "posix/process.h"
>>   #include "debug.h"
>>
>>   static DECLARE_WAIT_QUEUE_HEAD(join_all);
>> @@ -2520,6 +2522,43 @@ int xnthread_killall(int grace, int mask)
>>   }
>>   EXPORT_SYMBOL_GPL(xnthread_killall);
>>
>> +int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
>> +{
>> +	struct ksignal ksig;
>> +
>> +	unsigned int vector = trapnr;
>> +	unsigned int code = xnarch_fault_code(regs);
>> +	struct cobalt_ppd *sys_ppd;
>> +	int sig, ret = 0;
>> +	struct kernel_siginfo si;
>> +
>> +	code = xnarch_fault_code(regs);
>> +	ret = xnarch_setup_trap_info(vector, regs, code, &sig, &si);
>> +	if (ret || sig == 0)
>> +		return 1;
>> +
>> +	sys_ppd = cobalt_ppd_get(0);
>> +	if (sig >= _NSIG ||
>> +	    sys_ppd->sighand[sig] == NULL ||
>> +	    sys_ppd->sighand[sig] == SIG_DFL)
>> +		return 1;
>> +
>> +	if (sys_ppd->sigrestorer == NULL)
>> +		return 1;
>> +
>> +	ksig.sig = sig;
>> +	memcpy(&ksig.info, &si, sizeof(si));
>> +	ksig.ka.sa.sa_flags = SA_SIGINFO | SA_RESTORER;
>> +	ksig.ka.sa.sa_restorer = sys_ppd->sigrestorer;
>> +	ksig.ka.sa.sa_handler = sys_ppd->sighand[sig];
>> +
>> +	ret = dovetail_setup_rt_signal_frame(&ksig, regs);
>> +	if (ret)
>> +		return 1;
>> +
>> +	return 0;
>> +}
>> +
>>   /* Xenomai's generic personality. */
>>   struct xnthread_personality xenomai_personality = {
>>   	.name = "core",
>> diff --git a/lib/cobalt/arch/x86/Makefile.am b/lib/cobalt/arch/x86/Makefile.am
>> index a5095be3d..14f5eff97 100644
>> --- a/lib/cobalt/arch/x86/Makefile.am
>> +++ b/lib/cobalt/arch/x86/Makefile.am
>> @@ -2,7 +2,7 @@ noinst_LTLIBRARIES = libarch.la
>>
>>   libarch_la_LDFLAGS = @XENO_LIB_LDFLAGS@
>>
>> -libarch_la_SOURCES = features.c
>> +libarch_la_SOURCES = features.c sigreturn.c
>>
>>   libarch_la_CPPFLAGS =			\
>>   	@XENO_COBALT_CFLAGS@ 		\
>> diff --git a/lib/cobalt/arch/x86/sigreturn.c b/lib/cobalt/arch/x86/sigreturn.c
>> new file mode 100644
>> index 000000000..76292e145
>> --- /dev/null
>> +++ b/lib/cobalt/arch/x86/sigreturn.c
>> @@ -0,0 +1,32 @@
>> +#include <cobalt/uapi/syscall.h>
>> +#include "internal.h"
>> +
>> +extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__
>> ((visibility ("hidden")));
>> +
>> +#ifdef __x86_64__
>> +#define build_restorer(syscall_number)                                         \
>> +	asm(".text\n"                                                          \
>> +	    "    .align 16\n"                                                  \
>> +	    "__cobalt_sigreturn:\n"                                            \
>> +	    "    movq $ " #syscall_number ", %rax\n"                           \
>> +	    "    syscall")
>> +#endif
>> +
>> +#ifdef __i386__
>> +#define build_restorer(syscall_number)                                         \
>> +	asm(".text\n"                                                          \
>> +	    "    .align 16\n"                                                  \
>> +	    "__cobalt_sigreturn:\n"                                            \
>> +	    "    movl $ " #syscall_number ", %eax\n"                           \
>> +	    "    int  $0x80")
>> +#endif
>> +
>> +/*
>> + * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
>> + */
>> +build_restorer(0x10000078);
>> +
>> +void *cobalt_get_restorer(void)
>> +{
>> +	return &cobalt_sigreturn;
>> +}
>> diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
>> index acb3989f1..4782d154a 100644
>> --- a/lib/cobalt/internal.h
>> +++ b/lib/cobalt/internal.h
>> @@ -132,4 +132,6 @@ static inline bool cobalt_features_available(unsigned int
>> feat_mask)
>>   	return (cobalt_features & feat_mask) == feat_mask;
>>   }
>>
>> +extern void *cobalt_get_restorer(void);
>> +
>>   #endif /* _LIB_COBALT_INTERNAL_H */
>> diff --git a/lib/cobalt/signal.c b/lib/cobalt/signal.c
>> index 40d315ebb..af174d570 100644
>> --- a/lib/cobalt/signal.c
>> +++ b/lib/cobalt/signal.c
>> @@ -126,3 +126,16 @@ COBALT_IMPL(int, sigqueue, (pid_t pid, int sig, const
>> union sigval value))
>>
>>   	return 0;
>>   }
>> +
>> +int cobalt_rt_signal(int sig, void (*handler)(int, siginfo_t *, void *))
>> +{
>> +	int ret;
>> +
>> +	ret = XENOMAI_SYSCALL3(sc_cobalt_sigaction, sig, handler,
>> cobalt_get_restorer());
>> +	if (ret) {
>> +		errno = -ret;
>> +		return -1;
>> +	}
>> +
>> +	return 0;
>> +}
>> --
>> 2.25.1
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 2/3] [POC] Add rt_signal test
  2023-09-08 10:50 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
@ 2023-09-08 10:50 ` Johannes Kirchmair
  0 siblings, 0 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-09-08 10:50 UTC (permalink / raw)
  To: xenomai; +Cc: Johannes Kirchmair

This commit adds simple rt signal test for SIGFPE, SIGILL and SIGSEGV.

Signed-off-by: Johannes Kirchmair <johannes.kirchmair@sigmatek.at>
---
 configure.ac                               |   1 +
 testsuite/Makefile.am                      |   1 +
 testsuite/rt-signal-tests/Makefile.am      |  31 +++
 testsuite/rt-signal-tests/rt_signal_test.c | 231 +++++++++++++++++++++
 4 files changed, 264 insertions(+)
 create mode 100644 testsuite/rt-signal-tests/Makefile.am
 create mode 100644 testsuite/rt-signal-tests/rt_signal_test.c

diff --git a/configure.ac b/configure.ac
index 3ce34048e..3325482fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1007,6 +1007,7 @@ AC_CONFIG_FILES([ \
 	testsuite/switchtest/Makefile \
 	testsuite/gpiotest/Makefile \
 	testsuite/gpiobench/Makefile \
+	testsuite/rt-signal-tests/Makefile \
 	testsuite/spitest/Makefile \
 	testsuite/smokey/Makefile \
 	testsuite/smokey/arith/Makefile \
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 4932f6d33..59f36967a 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -5,6 +5,7 @@ if XENO_COBALT
 SUBDIRS += 		\
 	clocktest	\
 	gpiotest	\
+	rt-signal-tests	\
 	spitest		\
 	switchtest	\
 	xeno-test
diff --git a/testsuite/rt-signal-tests/Makefile.am b/testsuite/rt-signal-tests/Makefile.am
new file mode 100644
index 000000000..084347631
--- /dev/null
+++ b/testsuite/rt-signal-tests/Makefile.am
@@ -0,0 +1,31 @@
+testdir = @XENO_TEST_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rt_signal_test_fpe rt_signal_test_segfault rt_signal_test_ill
+
+alchemycppflags =              			 \
+	$(XENO_USER_CFLAGS)    			 \
+	-I$(top_srcdir)/include
+
+alchemyldadd =					\
+	@XENO_AUTOINIT_LDFLAGS@			\
+	$(XENO_POSIX_WRAPPERS)			\
+	../../lib/alchemy/libalchemy.la		\
+	../../lib/copperplate/libcopperplate.la	\
+	@XENO_CORE_LDADD@			\
+	@XENO_USER_LDADD@			\
+	-lrt -lpthread -lm
+
+rt_signal_test_fpe_SOURCES = rt_signal_test.c
+rt_signal_test_fpe_CPPFLAGS = $(alchemycppflags) -DTEST_FPE=1
+rt_signal_test_fpe_LDADD = $(alchemyldadd)
+
+rt_signal_test_segfault_SOURCES = rt_signal_test.c
+rt_signal_test_segfault_CPPFLAGS = $(alchemycppflags) -DTEST_SEGFAULT=1
+rt_signal_test_segfault_LDADD = $(alchemyldadd)
+
+rt_signal_test_ill_SOURCES = rt_signal_test.c
+rt_signal_test_ill_CPPFLAGS = $(alchemycppflags)
+rt_signal_test_ill_LDADD = $(alchemyldadd)
+
diff --git a/testsuite/rt-signal-tests/rt_signal_test.c b/testsuite/rt-signal-tests/rt_signal_test.c
new file mode 100644
index 000000000..ef569b30d
--- /dev/null
+++ b/testsuite/rt-signal-tests/rt_signal_test.c
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <copperplate/traceobj.h>
+#include <alchemy/task.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <asm/ucontext.h>
+
+#ifdef TEST_SEGFAULT
+#define TEST_SIGNAL SIGSEGV
+#elif defined(TEST_FPE)
+#define TEST_SIGNAL SIGFPE
+#else
+#define TEST_SIGNAL SIGILL
+#endif
+
+#define BIT_FAULT_HANDLER_ENTERD     1
+#define BIT_FAULT_HANDLER_FINISHED   2
+#define BIT_FAULT_HANDLER_WRONG_TASK 4
+#define BIT_FAULT_HANDLER_WRONG_SIG  8
+#define BIT_DOMAIN_SWITCH            16
+
+static RT_TASK t1;
+static sig_atomic_t status = 0;
+static sig_atomic_t cause = 0;
+
+// #define JMP_CLEANUP
+#ifdef JMP_CLEANUP
+static jmp_buf jmpenv;
+#endif
+
+static int status_ok(void)
+{
+	return status ==
+	       (BIT_FAULT_HANDLER_ENTERD | BIT_FAULT_HANDLER_FINISHED);
+}
+
+static const char *sigdebug_msg[] = {
+	[SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
+	[SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+	[SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+	[SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+	[SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
+	[SIGDEBUG_NOMLOCK] = "Xenomai: process memory not locked "
+			     "(missing mlockall?)",
+	[SIGDEBUG_WATCHDOG] = "Xenomai: watchdog triggered "
+			      "(period too short?)",
+};
+
+
+#ifndef JMP_CLEANUP
+static int get_step(void)
+{
+#ifdef TEST_SEGFAULT
+#if defined(__i386__) || defined(__x86_64__)
+	return 11;
+#else
+	return 4;
+#endif
+#elif defined(TEST_FPE)
+	return 2;
+#else
+#if defined(__i386__) || defined(__x86_64__)
+	return 2;
+#else
+	return 4;
+#endif
+#endif
+}
+
+static void do_cleanup(void *context)
+{
+	int step = 0;
+	struct ucontext *uc = context;
+
+	step = get_step();
+
+#if defined(__i386__)
+	uc->uc_mcontext.eip += step;
+#elif defined(__x86_64__)
+	uc->uc_mcontext.rip += step;
+#elif defined(__aarch64__)
+	uc->uc_mcontext.pc += step;
+#endif
+}
+#endif
+
+static void signal_handler(int sig, siginfo_t *info, void *context)
+{
+	RT_TASK *self;
+	(void)context;
+
+	if (sig == SIGDEBUG) {
+		cause = sigdebug_reason(info);
+
+		if (cause > SIGDEBUG_WATCHDOG)
+			cause = SIGDEBUG_UNDEFINED;
+
+		/* XXX: caused by rt_task_delete() */
+		if (!(status & BIT_FAULT_HANDLER_ENTERD) &&
+		    cause == SIGDEBUG_MIGRATE_SYSCALL) {
+			return;
+		}
+
+		status |= BIT_DOMAIN_SWITCH;
+	} else {
+		status |= BIT_FAULT_HANDLER_ENTERD;
+		if (sig != TEST_SIGNAL) {
+			status |= BIT_FAULT_HANDLER_WRONG_SIG;
+			return;
+		}
+
+		self = rt_task_self();
+
+		if (self == NULL || !rt_task_same(self, &t1)) {
+			status |= BIT_FAULT_HANDLER_WRONG_TASK;
+		} else {
+			status |= BIT_FAULT_HANDLER_FINISHED;
+		}
+
+#ifdef JMP_CLEANUP
+		longjmp(jmpenv, 1);
+#else
+		do_cleanup(context);
+#endif
+	}
+}
+
+static void do_div_by_0(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("xorl %eax, %eax\n\t"
+		"movl %eax, %ecx\n\t"
+		"cltd\n\t"
+		"idivl %ecx");
+#endif
+	//TODO find a cortex-A way to trigger an FPE
+}
+
+static void do_ill(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("ud2");
+#else
+	__asm__("udf #0xdead");
+#endif
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+static void do_segfault(void)
+{
+	*((int *)0x73) = 0xdecafbad;
+}
+#pragma GCC diagnostic pop
+
+static void task_proc(void *arg)
+{
+	int ret;
+	(void)arg;
+
+	ret = cobalt_rt_signal(TEST_SIGNAL, signal_handler);
+	assert(ret == 0);
+	(void)ret;
+
+#ifdef JMP_CLEANUP
+	if (setjmp(jmpenv) != 0)
+		return;
+#endif
+
+#ifdef TEST_SEGFAULT
+	do_segfault();
+#elif defined(TEST_FPE)
+	do_div_by_0();
+#else
+	do_ill();
+#endif
+
+	if (0) { // so we don't geht defined but not used errors
+		do_segfault();
+		do_div_by_0();
+		do_ill();
+	}
+}
+
+static int test_sucessfull(void)
+{
+	if (status_ok()) {
+		fputs("Test passed\n", stderr);
+		return 1;
+	}
+
+	if (!(status & BIT_FAULT_HANDLER_ENTERD))
+		fputs("Test failed: signal handler not invoked!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_TASK))
+		fputs("Test failed: Signal handler in wrong task!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_SIG))
+		fputs("Test failed: Signal handler of wrong signal!\n", stderr);
+	if ((status & BIT_DOMAIN_SWITCH)) {
+		fputs("Test failed: domain switch happened!\n", stderr);
+		fprintf(stderr, "Caused by: %s\n", sigdebug_msg[cause]);
+	}
+
+	return 0;
+}
+
+int main(void)
+{
+	struct sigaction sa;
+	int ret;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = signal_handler;
+	sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+	sigaction(TEST_SIGNAL, &sa, NULL);
+	sigaction(SIGDEBUG, &sa, NULL);
+
+	ret = rt_task_create(&t1, "rt-task", 0, 20, T_JOINABLE | T_WARNSW);
+	assert(ret == 0);
+
+	ret = rt_task_start(&t1, task_proc, NULL);
+	assert(ret == 0);
+
+	ret = rt_task_join(&t1);
+	assert(ret == 0);
+	(void)ret; // so the compiler does not complain about not checking ret
+
+	return test_sucessfull() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] [POC] Add rt_signal test
  2023-08-16 10:18 Johannes Kirchmair
@ 2023-08-16 10:18 ` Johannes Kirchmair
  0 siblings, 0 replies; 12+ messages in thread
From: Johannes Kirchmair @ 2023-08-16 10:18 UTC (permalink / raw)
  To: xenomai; +Cc: Johannes Kirchmair

This commit adds simple rt signal test for SIGFPE, SIGILL and SIGSEGV.
---
 configure.ac                               |   1 +
 testsuite/Makefile.am                      |   1 +
 testsuite/rt-signal-tests/Makefile.am      |  31 +++
 testsuite/rt-signal-tests/rt_signal_test.c | 231 +++++++++++++++++++++
 4 files changed, 264 insertions(+)
 create mode 100644 testsuite/rt-signal-tests/Makefile.am
 create mode 100644 testsuite/rt-signal-tests/rt_signal_test.c

diff --git a/configure.ac b/configure.ac
index 3ce34048e..3325482fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1007,6 +1007,7 @@ AC_CONFIG_FILES([ \
 	testsuite/switchtest/Makefile \
 	testsuite/gpiotest/Makefile \
 	testsuite/gpiobench/Makefile \
+	testsuite/rt-signal-tests/Makefile \
 	testsuite/spitest/Makefile \
 	testsuite/smokey/Makefile \
 	testsuite/smokey/arith/Makefile \
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 4932f6d33..59f36967a 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -5,6 +5,7 @@ if XENO_COBALT
 SUBDIRS += 		\
 	clocktest	\
 	gpiotest	\
+	rt-signal-tests	\
 	spitest		\
 	switchtest	\
 	xeno-test
diff --git a/testsuite/rt-signal-tests/Makefile.am b/testsuite/rt-signal-tests/Makefile.am
new file mode 100644
index 000000000..084347631
--- /dev/null
+++ b/testsuite/rt-signal-tests/Makefile.am
@@ -0,0 +1,31 @@
+testdir = @XENO_TEST_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+test_PROGRAMS = rt_signal_test_fpe rt_signal_test_segfault rt_signal_test_ill
+
+alchemycppflags =              			 \
+	$(XENO_USER_CFLAGS)    			 \
+	-I$(top_srcdir)/include
+
+alchemyldadd =					\
+	@XENO_AUTOINIT_LDFLAGS@			\
+	$(XENO_POSIX_WRAPPERS)			\
+	../../lib/alchemy/libalchemy.la		\
+	../../lib/copperplate/libcopperplate.la	\
+	@XENO_CORE_LDADD@			\
+	@XENO_USER_LDADD@			\
+	-lrt -lpthread -lm
+
+rt_signal_test_fpe_SOURCES = rt_signal_test.c
+rt_signal_test_fpe_CPPFLAGS = $(alchemycppflags) -DTEST_FPE=1
+rt_signal_test_fpe_LDADD = $(alchemyldadd)
+
+rt_signal_test_segfault_SOURCES = rt_signal_test.c
+rt_signal_test_segfault_CPPFLAGS = $(alchemycppflags) -DTEST_SEGFAULT=1
+rt_signal_test_segfault_LDADD = $(alchemyldadd)
+
+rt_signal_test_ill_SOURCES = rt_signal_test.c
+rt_signal_test_ill_CPPFLAGS = $(alchemycppflags)
+rt_signal_test_ill_LDADD = $(alchemyldadd)
+
diff --git a/testsuite/rt-signal-tests/rt_signal_test.c b/testsuite/rt-signal-tests/rt_signal_test.c
new file mode 100644
index 000000000..ef569b30d
--- /dev/null
+++ b/testsuite/rt-signal-tests/rt_signal_test.c
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <copperplate/traceobj.h>
+#include <alchemy/task.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <asm/ucontext.h>
+
+#ifdef TEST_SEGFAULT
+#define TEST_SIGNAL SIGSEGV
+#elif defined(TEST_FPE)
+#define TEST_SIGNAL SIGFPE
+#else
+#define TEST_SIGNAL SIGILL
+#endif
+
+#define BIT_FAULT_HANDLER_ENTERD     1
+#define BIT_FAULT_HANDLER_FINISHED   2
+#define BIT_FAULT_HANDLER_WRONG_TASK 4
+#define BIT_FAULT_HANDLER_WRONG_SIG  8
+#define BIT_DOMAIN_SWITCH            16
+
+static RT_TASK t1;
+static sig_atomic_t status = 0;
+static sig_atomic_t cause = 0;
+
+// #define JMP_CLEANUP
+#ifdef JMP_CLEANUP
+static jmp_buf jmpenv;
+#endif
+
+static int status_ok(void)
+{
+	return status ==
+	       (BIT_FAULT_HANDLER_ENTERD | BIT_FAULT_HANDLER_FINISHED);
+}
+
+static const char *sigdebug_msg[] = {
+	[SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
+	[SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
+	[SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
+	[SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
+	[SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
+	[SIGDEBUG_NOMLOCK] = "Xenomai: process memory not locked "
+			     "(missing mlockall?)",
+	[SIGDEBUG_WATCHDOG] = "Xenomai: watchdog triggered "
+			      "(period too short?)",
+};
+
+
+#ifndef JMP_CLEANUP
+static int get_step(void)
+{
+#ifdef TEST_SEGFAULT
+#if defined(__i386__) || defined(__x86_64__)
+	return 11;
+#else
+	return 4;
+#endif
+#elif defined(TEST_FPE)
+	return 2;
+#else
+#if defined(__i386__) || defined(__x86_64__)
+	return 2;
+#else
+	return 4;
+#endif
+#endif
+}
+
+static void do_cleanup(void *context)
+{
+	int step = 0;
+	struct ucontext *uc = context;
+
+	step = get_step();
+
+#if defined(__i386__)
+	uc->uc_mcontext.eip += step;
+#elif defined(__x86_64__)
+	uc->uc_mcontext.rip += step;
+#elif defined(__aarch64__)
+	uc->uc_mcontext.pc += step;
+#endif
+}
+#endif
+
+static void signal_handler(int sig, siginfo_t *info, void *context)
+{
+	RT_TASK *self;
+	(void)context;
+
+	if (sig == SIGDEBUG) {
+		cause = sigdebug_reason(info);
+
+		if (cause > SIGDEBUG_WATCHDOG)
+			cause = SIGDEBUG_UNDEFINED;
+
+		/* XXX: caused by rt_task_delete() */
+		if (!(status & BIT_FAULT_HANDLER_ENTERD) &&
+		    cause == SIGDEBUG_MIGRATE_SYSCALL) {
+			return;
+		}
+
+		status |= BIT_DOMAIN_SWITCH;
+	} else {
+		status |= BIT_FAULT_HANDLER_ENTERD;
+		if (sig != TEST_SIGNAL) {
+			status |= BIT_FAULT_HANDLER_WRONG_SIG;
+			return;
+		}
+
+		self = rt_task_self();
+
+		if (self == NULL || !rt_task_same(self, &t1)) {
+			status |= BIT_FAULT_HANDLER_WRONG_TASK;
+		} else {
+			status |= BIT_FAULT_HANDLER_FINISHED;
+		}
+
+#ifdef JMP_CLEANUP
+		longjmp(jmpenv, 1);
+#else
+		do_cleanup(context);
+#endif
+	}
+}
+
+static void do_div_by_0(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("xorl %eax, %eax\n\t"
+		"movl %eax, %ecx\n\t"
+		"cltd\n\t"
+		"idivl %ecx");
+#endif
+	//TODO find a cortex-A way to trigger an FPE
+}
+
+static void do_ill(void)
+{
+#if defined(__i386__) || defined (__x86_64__)
+	__asm__("ud2");
+#else
+	__asm__("udf #0xdead");
+#endif
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+static void do_segfault(void)
+{
+	*((int *)0x73) = 0xdecafbad;
+}
+#pragma GCC diagnostic pop
+
+static void task_proc(void *arg)
+{
+	int ret;
+	(void)arg;
+
+	ret = cobalt_rt_signal(TEST_SIGNAL, signal_handler);
+	assert(ret == 0);
+	(void)ret;
+
+#ifdef JMP_CLEANUP
+	if (setjmp(jmpenv) != 0)
+		return;
+#endif
+
+#ifdef TEST_SEGFAULT
+	do_segfault();
+#elif defined(TEST_FPE)
+	do_div_by_0();
+#else
+	do_ill();
+#endif
+
+	if (0) { // so we don't geht defined but not used errors
+		do_segfault();
+		do_div_by_0();
+		do_ill();
+	}
+}
+
+static int test_sucessfull(void)
+{
+	if (status_ok()) {
+		fputs("Test passed\n", stderr);
+		return 1;
+	}
+
+	if (!(status & BIT_FAULT_HANDLER_ENTERD))
+		fputs("Test failed: signal handler not invoked!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_TASK))
+		fputs("Test failed: Signal handler in wrong task!\n", stderr);
+	if ((status & BIT_FAULT_HANDLER_WRONG_SIG))
+		fputs("Test failed: Signal handler of wrong signal!\n", stderr);
+	if ((status & BIT_DOMAIN_SWITCH)) {
+		fputs("Test failed: domain switch happened!\n", stderr);
+		fprintf(stderr, "Caused by: %s\n", sigdebug_msg[cause]);
+	}
+
+	return 0;
+}
+
+int main(void)
+{
+	struct sigaction sa;
+	int ret;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = signal_handler;
+	sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+	sigaction(TEST_SIGNAL, &sa, NULL);
+	sigaction(SIGDEBUG, &sa, NULL);
+
+	ret = rt_task_create(&t1, "rt-task", 0, 20, T_JOINABLE | T_WARNSW);
+	assert(ret == 0);
+
+	ret = rt_task_start(&t1, task_proc, NULL);
+	assert(ret == 0);
+
+	ret = rt_task_join(&t1);
+	assert(ret == 0);
+	(void)ret; // so the compiler does not complain about not checking ret
+
+	return test_sucessfull() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-09-08 10:51 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-09 13:13 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
2023-05-09 13:13 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair
2023-05-09 13:13 ` [PATCH 3/3] [POC] add a tool to measure rt_signal latency Johannes Kirchmair
2023-05-09 13:17 ` [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
2023-05-12 17:38   ` Jan Kiszka
2023-05-15  6:50     ` Johannes Kirchmair
2023-05-15 10:38       ` Jan Kiszka
2023-05-16  6:46         ` Johannes Kirchmair
2023-05-16  6:52           ` Jan Kiszka
2023-08-09  9:50   ` Schaffner, Tobias
2023-08-16 10:18 Johannes Kirchmair
2023-08-16 10:18 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair
2023-09-08 10:50 [PATCH 1/3] [POC] test implementaion of rt-signals Johannes Kirchmair
2023-09-08 10:50 ` [PATCH 2/3] [POC] Add rt_signal test Johannes Kirchmair

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 NNTP newsgroup(s).