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