From 590ad70a9f696ce72f0693d96f7a5b1f71778009 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Mon, 24 Jun 2024 17:58:55 +0200
Subject: [PATCH] Fix trampoline for i686. Ctrl-C now works.

---
 redox-rt/src/arch/i686.rs   | 98 +++++++++++++++++++++++++++++++++++--
 redox-rt/src/arch/x86_64.rs | 14 +++---
 redox-rt/src/signal.rs      | 11 ++++-
 3 files changed, 109 insertions(+), 14 deletions(-)

diff --git a/redox-rt/src/arch/i686.rs b/redox-rt/src/arch/i686.rs
index 27060616..b0916720 100644
--- a/redox-rt/src/arch/i686.rs
+++ b/redox-rt/src/arch/i686.rs
@@ -1,4 +1,6 @@
-use syscall::error::*;
+use core::mem::offset_of;
+
+use syscall::*;
 
 use crate::proc::{fork_inner, FdGuard};
 use crate::signal::{inner_fastcall, RtSigarea};
@@ -97,17 +99,105 @@ asmfunction!(__relibc_internal_fork_ret: ["
     ret
 "] <= [child_hook = sym child_hook]);
 asmfunction!(__relibc_internal_sigentry: ["
-    sub esp, 512
+    // Read pending half of first signal. This can be done nonatomically wrt the mask bits, since
+    // only this thread is allowed to modify the latter.
+
+    // Read first signal word
+    mov eax, gs:[{tcb_sc_off} + {sc_word}]
+    mov edx, gs:[{tcb_sc_off} + {sc_word} + 4]
+    not edx
+    and eax, edx
+    and eax, {SIGW0_PENDING_MASK}
+    bsf eax, eax
+    jnz 2f
+
+    // Read second signal word
+    mov eax, gs:[{tcb_sc_off} + {sc_word} + 8]
+    mov edx, gs:[{tcb_sc_off} + {sc_word} + 12]
+    not edx
+    and eax, edx
+    and eax, {SIGW1_PENDING_MASK}
+    bsf eax, eax
+    jz 7f
+    add eax, 32
+2:
+    and esp, -{STACK_ALIGN}
+    bt gs:[{tcb_sa_off} + {sa_onstack}], eax
+    jnc 4f
+
+    mov edx, gs:[{tcb_sa_off} + {sa_altstack_top}]
+    cmp esp, edx
+    ja 3f
+
+    cmp esp, gs:[{tcb_sa_off} + {sa_altstack_bottom}]
+    jnbe 4f
+3:
+    mov esp, edx
+4:
+    // Now that we have a stack, we can finally start populating the signal stack.
+    push fs
+    .byte 0x66, 0x6a, 0x00 // pushw 0
+    push ss
+    .byte 0x66, 0x6a, 0x00 // pushw 0
+    push dword ptr gs:[{tcb_sc_off} + {sc_saved_esp}]
+    push dword ptr gs:[{tcb_sc_off} + {sc_saved_eflags}]
+    push cs
+    .byte 0x66, 0x6a, 0x00 // pushw 0
+    push dword ptr gs:[{tcb_sc_off} + {sc_saved_eip}]
+
+    push dword ptr gs:[{tcb_sc_off} + {sc_saved_edx}]
+    push ecx
+    push dword ptr gs:[{tcb_sc_off} + {sc_saved_eax}]
+    push ebx
+    push edi
+    push esi
+    push ebp
+
+    push eax
+    sub esp, 512 + 8
     fxsave [esp]
 
     mov ecx, esp
     call {inner}
 
-    add esp, 512
     fxrstor [esp]
+    add esp, 512 + 12
 
+    pop ebp
+    pop esi
+    pop edi
+    pop ebx
+    pop eax
+    pop ecx
+    pop edx
+
+    pop dword ptr gs:[{tcb_sa_off} + {sa_tmp}]
+    add esp, 4
+    popf
+    pop esp
+    jmp dword ptr gs:[{tcb_sa_off} + {sa_tmp}]
+7:
     ud2
-"] <= [inner = sym inner_fastcall]);
+"] <= [
+    inner = sym inner_fastcall,
+    sa_tmp = const offset_of!(SigArea, tmp),
+    sa_altstack_top = const offset_of!(SigArea, altstack_top),
+    sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
+    sa_onstack = const offset_of!(SigArea, onstack),
+    sc_saved_eax = const offset_of!(Sigcontrol, saved_scratch_a),
+    sc_saved_edx = const offset_of!(Sigcontrol, saved_scratch_b),
+    sc_saved_eflags = const offset_of!(Sigcontrol, saved_flags),
+    sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
+    sc_saved_esp = const offset_of!(Sigcontrol, saved_sp),
+    sc_word = const offset_of!(Sigcontrol, word),
+    tcb_sa_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch),
+    tcb_sc_off = const offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control),
+    SIGW0_PENDING_MASK = const !(
+        SIGW0_TSTP_IS_STOP_BIT | SIGW0_TTIN_IS_STOP_BIT | SIGW0_TTOU_IS_STOP_BIT | SIGW0_NOCLDSTOP_BIT | SIGW0_UNUSED1 | SIGW0_UNUSED2
+    ),
+    SIGW1_PENDING_MASK = const !0,
+    STACK_ALIGN = const 16,
+]);
 
 asmfunction!(__relibc_internal_rlct_clone_ret -> usize: ["
     # Load registers
diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs
index a5b2e7e7..a2cdf1ad 100644
--- a/redox-rt/src/arch/x86_64.rs
+++ b/redox-rt/src/arch/x86_64.rs
@@ -153,27 +153,25 @@ asmfunction!(__relibc_internal_sigentry: ["
     jnz 7f
     add eax, 32
 2:
+    sub rsp, {REDZONE_SIZE}
+    and rsp, -{STACK_ALIGN}
+
     // By now we have selected a signal, stored in eax (6-bit). We now need to choose whether or
     // not to switch to the alternate signal stack. If SA_ONSTACK is clear for this signal, then
     // skip the sigaltstack logic.
     bt fs:[{tcb_sa_off} + {sa_onstack}], eax
-    jc 3f
+    jnc 4f
 
     // Otherwise, the altstack is already active. The sigaltstack being disabled, is equivalent
     // to setting 'top' to usize::MAX and 'bottom' to 0.
 
-    sub rsp, {REDZONE_SIZE}
-    and rsp, -{STACK_ALIGN}
-    jmp 4f
-3:
     // If current RSP is above altstack region, switch to altstack
     mov rdx, fs:[{tcb_sa_off} + {sa_altstack_top}]
-    cmp rdx, rsp
+    cmp rsp, rdx
     cmova rsp, rdx
 
     // If current RSP is below altstack region, also switch to altstack
-    mov rdx, fs:[{tcb_sa_off} + {sa_altstack_bottom}]
-    cmp rdx, rsp
+    cmp rsp, fs:[{tcb_sa_off} + {sa_altstack_bottom}]
     cmovbe rsp, rdx
 
     .p2align 4
diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 6171630b..2ffd3031 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -34,7 +34,12 @@ pub struct SigStack {
     #[cfg(target_arch = "x86")]
     fx: [u8; 512],
 
+    #[cfg(target_arch = "x86_64")]
     _pad: [usize; 3], // pad to 192 = 3 * 64 = 168 + 24 bytes
+
+    #[cfg(target_arch = "x86")]
+    _pad: [usize; 2], // pad to 192 = 3 * 64 = 168 + 24 bytes
+
     sig_num: usize,
     regs: IntRegisters, // 160 bytes currently
 }
@@ -310,15 +315,17 @@ pub fn setup_sighandler(area: &RtSigarea) {
         let mut sigactions = SIGACTIONS.lock();
     }
     let arch = unsafe { &mut *area.arch.get() };
-
-    #[cfg(target_arch = "x86_64")]
     {
         // The asm decides whether to use the altstack, based on whether the saved stack pointer
         // was already on that stack. Thus, setting the altstack to the entire address space, is
         // equivalent to not using any altstack at all (the default).
         arch.altstack_top = usize::MAX;
         arch.altstack_bottom = 0;
+        arch.onstack = 0;
+    }
 
+    #[cfg(target_arch = "x86_64")]
+    {
         let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx;
         CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed);
     }
-- 
GitLab