From 2f529f9b558ca1c1bd74be7437a84e4711743404 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 01 Nov 2024 02:11:33 +0000
Subject: [PATCH] add xenomai
---
kernel/arch/x86/kernel/traps.c | 159 ++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 134 insertions(+), 25 deletions(-)
diff --git a/kernel/arch/x86/kernel/traps.c b/kernel/arch/x86/kernel/traps.c
index 2a39a2d..8ac9772 100644
--- a/kernel/arch/x86/kernel/traps.c
+++ b/kernel/arch/x86/kernel/traps.c
@@ -74,14 +74,22 @@
static inline void cond_local_irq_enable(struct pt_regs *regs)
{
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_enable();
+ if (regs->flags & X86_EFLAGS_IF) {
+ if (running_inband())
+ local_irq_enable_full();
+ else
+ hard_local_irq_enable();
+ }
}
static inline void cond_local_irq_disable(struct pt_regs *regs)
{
- if (regs->flags & X86_EFLAGS_IF)
- local_irq_disable();
+ if (regs->flags & X86_EFLAGS_IF) {
+ if (running_inband())
+ local_irq_disable_full();
+ else
+ hard_local_irq_disable();
+ }
}
__always_inline int is_valid_bugaddr(unsigned long addr)
@@ -148,6 +156,39 @@
}
}
+static __always_inline
+bool mark_trap_entry(int trapnr, struct pt_regs *regs)
+{
+ oob_trap_notify(trapnr, regs);
+
+ if (likely(running_inband())) {
+ hard_cond_local_irq_enable();
+ return true;
+ }
+
+ return false;
+}
+
+static __always_inline
+void mark_trap_exit(int trapnr, struct pt_regs *regs)
+{
+ oob_trap_unwind(trapnr, regs);
+ hard_cond_local_irq_disable();
+}
+
+static __always_inline
+bool mark_trap_entry_raw(int trapnr, struct pt_regs *regs)
+{
+ oob_trap_notify(trapnr, regs);
+ return running_inband();
+}
+
+static __always_inline
+void mark_trap_exit_raw(int trapnr, struct pt_regs *regs)
+{
+ oob_trap_unwind(trapnr, regs);
+}
+
static void
do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
long error_code, int sicode, void __user *addr)
@@ -171,12 +212,17 @@
{
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
+ if (!mark_trap_entry(trapnr, regs))
+ return;
+
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) !=
NOTIFY_STOP) {
cond_local_irq_enable(regs);
do_trap(trapnr, signr, str, regs, error_code, sicode, addr);
cond_local_irq_disable(regs);
}
+
+ mark_trap_exit(trapnr, regs);
}
/*
@@ -230,14 +276,22 @@
* Since we're emulating a CALL with exceptions, restore the interrupt
* state to what it was at the exception site.
*/
- if (regs->flags & X86_EFLAGS_IF)
- raw_local_irq_enable();
+ if (regs->flags & X86_EFLAGS_IF) {
+ if (running_oob())
+ hard_local_irq_enable();
+ else
+ local_irq_enable_full();
+ }
if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
regs->ip += LEN_UD2;
handled = true;
}
- if (regs->flags & X86_EFLAGS_IF)
- raw_local_irq_disable();
+ if (regs->flags & X86_EFLAGS_IF) {
+ if (running_oob())
+ hard_local_irq_disable();
+ else
+ local_irq_disable_full();
+ }
instrumentation_end();
return handled;
@@ -251,15 +305,26 @@
* We use UD2 as a short encoding for 'CALL __WARN', as such
* handle it before exception entry to avoid recursive WARN
* in case exception entry is the one triggering WARNs.
+ *
+ * dovetail: handle_bug() may run oob, so we do not downgrade
+ * in-band upon a failed __WARN assertion since it might have
+ * tripped in a section of code which would not be happy to
+ * switch stage. However, anything else should be notified to
+ * the core, because the kernel execution might be about to
+ * stop, so we'd need to switch in-band to get any output
+ * before this happens.
*/
if (!user_mode(regs) && handle_bug(regs))
return;
- state = irqentry_enter(regs);
- instrumentation_begin();
- handle_invalid_op(regs);
- instrumentation_end();
- irqentry_exit(regs, state);
+ if (mark_trap_entry_raw(X86_TRAP_UD, regs)) {
+ state = irqentry_enter(regs);
+ instrumentation_begin();
+ handle_invalid_op(regs);
+ instrumentation_end();
+ irqentry_exit(regs, state);
+ mark_trap_exit_raw(X86_TRAP_UD, regs);
+ }
}
DEFINE_IDTENTRY(exc_coproc_segment_overrun)
@@ -290,8 +355,11 @@
{
char *str = "alignment check";
- if (notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_AC, SIGBUS) == NOTIFY_STOP)
+ if (!mark_trap_entry(X86_TRAP_AC, regs))
return;
+
+ if (notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_AC, SIGBUS) == NOTIFY_STOP)
+ goto mark_exit;
if (!user_mode(regs))
die("Split lock detected\n", regs, error_code);
@@ -306,6 +374,9 @@
out:
local_irq_disable();
+
+mark_exit:
+ mark_trap_exit(X86_TRAP_AC, regs);
}
#ifdef CONFIG_VMAP_STACK
@@ -341,6 +412,9 @@
*
* The 32bit #DF shim provides CR2 already as an argument. On 64bit it needs
* to be read before doing anything else.
+ *
+ * Dovetail: do not even ask the companion core to try restoring the
+ * in-band stage on double-fault, this would be a lost cause.
*/
DEFINE_IDTENTRY_DF(exc_double_fault)
{
@@ -465,9 +539,12 @@
DEFINE_IDTENTRY(exc_bounds)
{
+ if (!mark_trap_entry(X86_TRAP_BR, regs))
+ return;
+
if (notify_die(DIE_TRAP, "bounds", regs, 0,
X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP)
- return;
+ goto out;
cond_local_irq_enable(regs);
if (!user_mode(regs))
@@ -476,6 +553,8 @@
do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, 0, 0, NULL);
cond_local_irq_disable(regs);
+out:
+ mark_trap_exit(X86_TRAP_BR, regs);
}
enum kernel_gp_hint {
@@ -570,9 +649,9 @@
}
if (v8086_mode(regs)) {
- local_irq_enable();
+ local_irq_enable_full();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
- local_irq_disable();
+ local_irq_disable_full();
return;
}
@@ -585,9 +664,12 @@
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_GP;
+ if (!mark_trap_entry(X86_TRAP_GP, regs))
+ goto exit;
+
show_signal(tsk, SIGSEGV, "", desc, regs, error_code);
force_sig(SIGSEGV);
- goto exit;
+ goto mark_exit;
}
if (fixup_exception(regs, X86_TRAP_GP, error_code, 0))
@@ -605,9 +687,12 @@
kprobe_fault_handler(regs, X86_TRAP_GP))
goto exit;
+ if (!mark_trap_entry(X86_TRAP_GP, regs))
+ goto exit;
+
ret = notify_die(DIE_GPF, desc, regs, error_code, X86_TRAP_GP, SIGSEGV);
if (ret == NOTIFY_STOP)
- goto exit;
+ goto mark_exit;
if (error_code)
snprintf(desc, sizeof(desc), "segment-related " GPFSTR);
@@ -629,6 +714,8 @@
die_addr(desc, regs, error_code, gp_addr);
+mark_exit:
+ mark_trap_exit(X86_TRAP_GP, regs);
exit:
cond_local_irq_disable(regs);
}
@@ -673,6 +760,9 @@
if (poke_int3_handler(regs))
return;
+ if (!mark_trap_entry_raw(X86_TRAP_BP, regs))
+ return;
+
/*
* irqentry_enter_from_user_mode() uses static_branch_{,un}likely()
* and therefore can trigger INT3, hence poke_int3_handler() must
@@ -695,6 +785,8 @@
instrumentation_end();
irqentry_nmi_exit(regs, irq_state);
}
+
+ mark_trap_exit_raw(X86_TRAP_BP, regs);
}
#ifdef CONFIG_X86_64
@@ -999,7 +1091,7 @@
goto out;
/* It's safe to allow irq's after DR6 has been saved */
- local_irq_enable();
+ local_irq_enable_full();
if (v8086_mode(regs)) {
handle_vm86_trap((struct kernel_vm86_regs *)regs, 0, X86_TRAP_DB);
@@ -1012,7 +1104,7 @@
send_sigtrap(regs, 0, get_si_code(dr6));
out_irq:
- local_irq_disable();
+ local_irq_disable_full();
out:
instrumentation_end();
irqentry_exit_to_user_mode(regs);
@@ -1022,13 +1114,19 @@
/* IST stack entry */
DEFINE_IDTENTRY_DEBUG(exc_debug)
{
- exc_debug_kernel(regs, debug_read_clear_dr6());
+ if (mark_trap_entry_raw(X86_TRAP_DB, regs)) {
+ exc_debug_kernel(regs, debug_read_clear_dr6());
+ mark_trap_exit_raw(X86_TRAP_DB, regs);
+ }
}
/* User entry, runs on regular task stack */
DEFINE_IDTENTRY_DEBUG_USER(exc_debug)
{
- exc_debug_user(regs, debug_read_clear_dr6());
+ if (mark_trap_entry_raw(X86_TRAP_DB, regs)) {
+ exc_debug_user(regs, debug_read_clear_dr6());
+ mark_trap_exit_raw(X86_TRAP_DB, regs);
+ }
}
#else
/* 32 bit does not have separate entry points. */
@@ -1062,13 +1160,16 @@
if (fixup_exception(regs, trapnr, 0, 0))
goto exit;
+ if (!mark_trap_entry(trapnr, regs))
+ goto exit;
+
task->thread.error_code = 0;
task->thread.trap_nr = trapnr;
if (notify_die(DIE_TRAP, str, regs, 0, trapnr,
SIGFPE) != NOTIFY_STOP)
die(str, regs, 0);
- goto exit;
+ goto mark_exit;
}
/*
@@ -1084,8 +1185,13 @@
if (!si_code)
goto exit;
+ if (!mark_trap_entry(trapnr, regs))
+ goto exit;
+
force_sig_fault(SIGFPE, si_code,
(void __user *)uprobe_get_trap_addr(regs));
+mark_exit:
+ mark_trap_exit(trapnr, regs);
exit:
cond_local_irq_disable(regs);
}
@@ -1158,7 +1264,10 @@
* to kill the task than getting stuck in a never-ending
* loop of #NM faults.
*/
- die("unexpected #NM exception", regs, 0);
+ if (mark_trap_entry(X86_TRAP_NM, regs)) {
+ die("unexpected #NM exception", regs, 0);
+ mark_trap_exit(X86_TRAP_NM, regs);
+ }
}
}
--
Gitblit v1.6.2