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; 30+ 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] 30+ messages in thread
* [PATCH 1/3] [POC] test implementaion of rt-signals
@ 2023-08-16 10:18 Johannes Kirchmair
  2023-08-16 11:24 ` Florian Bezdeka
                   ` (3 more replies)
  0 siblings, 4 replies; 30+ messages in thread
From: Johannes Kirchmair @ 2023-08-16 10:18 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/signal.h                  |  1 +
 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          | 37 +++++++++
 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               | 36 +++++++++
 lib/cobalt/internal.h                         |  2 +
 lib/cobalt/signal.c                           | 13 ++++
 18 files changed, 282 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/signal.h b/include/cobalt/uapi/signal.h
index 8a7ea15a4..1afb6050a 100644
--- a/include/cobalt/uapi/signal.h
+++ b/include/cobalt/uapi/signal.h
@@ -68,6 +68,7 @@
 #define SIGDEBUG_RESCNT_IMBALANCE	7
 #define SIGDEBUG_LOCK_BREAK		8
 #define SIGDEBUG_MUTEX_SLEEP		9
+#define SIGDEBUG_SIGRESTOR		10
 
 #define COBALT_DELAYMAX			2147483647U
 
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index 3e65efaab..f14bd8ffe 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -142,6 +142,12 @@
 #define sc_cobalt_timerfd_gettime64		119
 #define sc_cobalt_pselect64			120
 
+/*
+ * Sigmatek specific syscalls
+ */
+#define sc_cobalt_sigreturn			121
+#define sc_cobalt_sigaction			122
+
 #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..140016460
--- /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(), SIGDEBUG_SIGRESTOR);
+	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..3b8cd3330
--- /dev/null
+++ b/kernel/cobalt/arch/x86/signal_ia64.c
@@ -0,0 +1,37 @@
+// 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)
+{
+	int ret;
+
+	ret = dovetail_restore_rt_signal_frame(regs);
+	if (ret < 0)
+		goto badframe;
+
+	return regs->ax;
+
+badframe:
+	xnthread_call_mayday(xnthread_current(), SIGDEBUG_SIGRESTOR);
+	return -1;
+
+}
+
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 780d276b1..7c858f904 100644
--- a/kernel/cobalt/posix/syscall32.c
+++ b/kernel/cobalt/posix/syscall32.c
@@ -705,6 +705,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..df961469e
--- /dev/null
+++ b/lib/cobalt/arch/x86/sigreturn.c
@@ -0,0 +1,36 @@
+#include <cobalt/uapi/syscall.h>
+#include "internal.h"
+
+extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__ ((visibility ("hidden")));
+
+#define TO_STR(x) #x
+
+#ifdef __x86_64__
+#define build_restorer(syscall_bit, syscall)                                   \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movq $ " TO_STR(syscall_bit) ", %rax\n"                       \
+	    "    orq $ " TO_STR(syscall) ", %rax\n"                            \
+	    "    syscall")
+#endif
+
+#ifdef __i386__
+#define build_restorer(syscall_bit, syscall)                                   \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movl $ " TO_STR(syscall_bit) ", %eax\n"                       \
+	    "    orl $ " TO_STR(syscall) ", %eax\n"                            \
+	    "    int  $0x80")
+#endif
+
+/*
+ * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
+ */
+build_restorer(__COBALT_SYSCALL_BIT, sc_cobalt_sigreturn);
+
+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] 30+ messages in thread
* [PATCH 1/3] [POC] test implementaion of rt-signals
@ 2023-09-08 10:50 Johannes Kirchmair
  2023-09-08 10:54 ` Johannes Kirchmair
  2023-09-09 11:35 ` Jan Kiszka
  0 siblings, 2 replies; 30+ messages in thread
From: Johannes Kirchmair @ 2023-09-08 10:50 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                 |  2 +
 kernel/cobalt/arch/x86/Makefile               |  2 +-
 .../arch/x86/include/asm/xenomai/thread.h     |  3 ++
 kernel/cobalt/arch/x86/signal.c               | 51 +++++++++++++++++++
 kernel/cobalt/dovetail/kevents.c              |  3 ++
 kernel/cobalt/posix/syscall.c                 | 32 ++++++++++++
 kernel/cobalt/thread.c                        | 38 ++++++++++++++
 kernel/cobalt/trace/cobalt-posix.h            |  4 +-
 lib/cobalt/arch/x86/Makefile.am               |  2 +-
 lib/cobalt/arch/x86/sigreturn.c               | 36 +++++++++++++
 lib/cobalt/internal.h                         |  2 +
 lib/cobalt/signal.c                           | 13 +++++
 15 files changed, 192 insertions(+), 3 deletions(-)
 create mode 100644 kernel/cobalt/arch/x86/signal.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 3e65efaab..3913cc610 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -141,6 +141,8 @@
 #define sc_cobalt_timerfd_settime64		118
 #define sc_cobalt_timerfd_gettime64		119
 #define sc_cobalt_pselect64			120
+#define sc_cobalt_sigreturn			121
+#define sc_cobalt_sigaction			122
 
 #define __NR_COBALT_SYSCALLS			128 /* Power of 2 */
 
diff --git a/kernel/cobalt/arch/x86/Makefile b/kernel/cobalt/arch/x86/Makefile
index 93929b645..e3d8eb476 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.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..70f3df2f1 100644
--- a/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
+++ b/kernel/cobalt/arch/x86/include/asm/xenomai/thread.h
@@ -28,5 +28,8 @@
 #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);
 
 #endif /* !_COBALT_X86_ASM_THREAD_H */
diff --git a/kernel/cobalt/arch/x86/signal.c b/kernel/cobalt/arch/x86/signal.c
new file mode 100644
index 000000000..2e8fdc571
--- /dev/null
+++ b/kernel/cobalt/arch/x86/signal.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#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>
+#include <asm/trapnr.h>
+
+int xnarch_setup_trap_info(unsigned int vector, struct pt_regs *regs,
+			   long errcode, int *sig, struct kernel_siginfo *info)
+{
+	switch (vector) {
+	case X86_TRAP_DE: /* 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 X86_TRAP_UD: /* 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 X86_TRAP_MF:
+		*sig = SIGFPE;
+
+		info->si_signo = *sig;
+		info->si_errno = 0;
+		info->si_code = 0;
+		info->si_addr = (void __user *)regs->ip;
+		return 0;
+        case X86_TRAP_PF:
+                *sig = SIGSEGV;
+                info->si_signo = *sig;
+                info->si_errno = errcode;
+                info->si_code = 0;
+                info->si_addr = 0;
+                return 0;
+	default:
+		break;
+	}
+
+	return -ENOSYS;
+}
+
diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c
index 4da4f51b7..09eb12acb 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,
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 46c4998e4..d570bd595 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -277,6 +277,38 @@ static COBALT_SYSCALL(serialdbg, current,
 	return 0;
 }
 
+static COBALT_SYSCALL(sigreturn, current, (void))
+{
+	struct pt_regs *regs = task_pt_regs(current);
+	int ret;
+
+	ret = dovetail_restore_rt_signal_frame(regs);
+	if (ret < 0)
+		goto badframe;
+
+	return __xn_reg_rval(regs);
+
+badframe:
+	xnthread_signal(xnthread_current(), SIGSEGV, 0);
+	return -1;
+}
+
+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/thread.c b/kernel/cobalt/thread.c
index 41804b24f..ae8fa5c88 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,42 @@ int xnthread_killall(int grace, int mask)
 }
 EXPORT_SYMBOL_GPL(xnthread_killall);
 
+int xnthread_handle_rt_signals(unsigned int trapnr, struct pt_regs *regs)
+{
+	unsigned int code = xnarch_fault_code(regs);
+	unsigned int vector = trapnr;
+	struct cobalt_ppd *sys_ppd;
+	struct kernel_siginfo si;
+	struct ksignal ksig;
+	int sig, ret = 0;
+
+	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/kernel/cobalt/trace/cobalt-posix.h b/kernel/cobalt/trace/cobalt-posix.h
index 47dc77e1c..8eda3bb27 100644
--- a/kernel/cobalt/trace/cobalt-posix.h
+++ b/kernel/cobalt/trace/cobalt-posix.h
@@ -173,7 +173,9 @@
 		__cobalt_symbolic_syscall(timer_gettime64),		\
 		__cobalt_symbolic_syscall(timerfd_settime64),		\
 		__cobalt_symbolic_syscall(timerfd_gettime64),		\
-		__cobalt_symbolic_syscall(pselect64))
+		__cobalt_symbolic_syscall(pselect64),			\
+		__cobalt_symbolic_syscall(sigreturn),			\
+		__cobalt_symbolic_syscall(sigaction))
 
 DECLARE_EVENT_CLASS(cobalt_syscall_entry,
 	TP_PROTO(unsigned int nr),
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..df961469e
--- /dev/null
+++ b/lib/cobalt/arch/x86/sigreturn.c
@@ -0,0 +1,36 @@
+#include <cobalt/uapi/syscall.h>
+#include "internal.h"
+
+extern void cobalt_sigreturn (void) asm ("__cobalt_sigreturn") __attribute__ ((visibility ("hidden")));
+
+#define TO_STR(x) #x
+
+#ifdef __x86_64__
+#define build_restorer(syscall_bit, syscall)                                   \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movq $ " TO_STR(syscall_bit) ", %rax\n"                       \
+	    "    orq $ " TO_STR(syscall) ", %rax\n"                            \
+	    "    syscall")
+#endif
+
+#ifdef __i386__
+#define build_restorer(syscall_bit, syscall)                                   \
+	asm(".text\n"                                                          \
+	    "    .align 16\n"                                                  \
+	    "__cobalt_sigreturn:\n"                                            \
+	    "    movl $ " TO_STR(syscall_bit) ", %eax\n"                       \
+	    "    orl $ " TO_STR(syscall) ", %eax\n"                            \
+	    "    int  $0x80")
+#endif
+
+/*
+ * __COBALT_SYSCALL_BIT | sc_cobalt_sigreturn
+ */
+build_restorer(__COBALT_SYSCALL_BIT, sc_cobalt_sigreturn);
+
+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] 30+ messages in thread

end of thread, other threads:[~2024-03-05 17:14 UTC | newest]

Thread overview: 30+ 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 11:24 ` Florian Bezdeka
2023-08-16 11:36   ` Jan Kiszka
2023-08-16 11:59     ` Johannes Kirchmair
2023-09-07 10:48   ` Johannes Kirchmair
2023-09-11  8:41     ` Florian Bezdeka
2023-09-01 12:00 ` Jan Kiszka
2023-09-01 13:38   ` Jan Kiszka
2023-09-04  6:55   ` Johannes Kirchmair
2023-09-07 13:39     ` Jan Kiszka
2023-09-07 13:58       ` Johannes Kirchmair
2023-09-01 13:51 ` Jan Kiszka
2023-09-01 14:11   ` Jan Kiszka
2023-09-04  7:04     ` Johannes Kirchmair
2024-03-05 15:54 ` Richard Weinberger
2024-03-05 17:05   ` Jan Kiszka
2024-03-05 17:14     ` Richard Weinberger
2023-09-08 10:50 Johannes Kirchmair
2023-09-08 10:54 ` Johannes Kirchmair
2023-09-09 11:35 ` Jan Kiszka

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).