diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs index 97e277a0453e5f179d88b335a64fbeb5d52c891a..2999115c36508d048c38ec8bfb850c8be96b59f3 100644 --- a/generic-rt/src/lib.rs +++ b/generic-rt/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![feature(core_intrinsics)] use core::arch::asm; use core::mem::{self, offset_of}; @@ -70,4 +71,42 @@ impl<Os> GenericTcb<Os> { Some(tcb_ptr) } } + pub unsafe fn current() -> Option<&'static mut Self> { + Some(&mut *Self::current_ptr()?) + } +} +pub fn panic_notls(msg: impl core::fmt::Display) -> ! { + //eprintln!("panicked in ld.so: {}", msg); + + core::intrinsics::abort(); +} + +pub trait ExpectTlsFree { + type Unwrapped; + + fn expect_notls(self, msg: &str) -> Self::Unwrapped; } +impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Ok(t) => t, + Err(err) => panic_notls(format_args!( + "{}: expect failed for Result with err: {:?}", + msg, err + )), + } + } +} +impl<T> ExpectTlsFree for Option<T> { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Some(t) => t, + None => panic_notls(format_args!("{}: expect failed for Option", msg)), + } + } +} + diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index de94685416ba6384020d1b245d737ffc14e9fb14..c1a11cd278e89760d09d9adef203c81e6c163372 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -16,6 +16,7 @@ pub struct SigArea { altstack_top: usize, altstack_bottom: usize, tmp: usize, + pub disable_signals_depth: u64, } /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS @@ -145,10 +146,10 @@ asmfunction!(__relibc_internal_sigentry: [" // // Now that we have a stack, we can finally start initializing the signal stack! - push ss + push 0 // SS push [rax + {tcb_sc_off} + {sc_saved_rsp}] push [rax + {tcb_sc_off} + {sc_saved_rflags}] - push cs + push 0 // CS push [rax + {tcb_sc_off} + {sc_saved_rip}] push rdi @@ -176,7 +177,7 @@ asmfunction!(__relibc_internal_sigentry: [" rep stosb // TODO: self-modifying? - cmp byte ptr [{supports_xsave}], 0 + cmp byte ptr [rip + {supports_xsave}], 0 je 3f mov eax, 0xffffffff @@ -208,11 +209,11 @@ asmfunction!(__relibc_internal_sigentry: [" pop rsi pop rdi - pop gs:[{tcb_sa_off} + {sa_tmp}] + pop qword ptr gs:[{tcb_sa_off} + {sa_tmp}] add rsp, 8 popfq pop rsp - jmp gs:[{tcb_sa_off} + {sa_tmp}] + jmp qword ptr gs:[{tcb_sa_off} + {sa_tmp}] 3: fxsave64 [rsp] diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 84c7eac9eb3ee8c6edf906dfaec9741e32218100..2d06cc8ec3300a0649174deb69f2488e2bd4b760 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -1,8 +1,8 @@ #![no_std] -#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell, thread_local)] +#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell)] #![forbid(unreachable_patterns)] -use generic_rt::GenericTcb; +use generic_rt::{ExpectTlsFree, GenericTcb}; use self::signal::RtSigarea; @@ -39,3 +39,75 @@ pub mod sync; pub mod thread; pub type Tcb = GenericTcb<RtSigarea>; + +/// OS and architecture specific code to activate TLS - Redox aarch64 +#[cfg(target_arch = "aarch64")] +pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) { + // Uses ABI page + let abi_ptr = tls_end - tls_len - 16; + ptr::write(abi_ptr as *mut usize, tls_end); + asm!( + "msr tpidr_el0, {}", + in(reg) abi_ptr, + ); +} + +/// OS and architecture specific code to activate TLS - Redox x86 +#[cfg(target_arch = "x86")] +pub unsafe fn tcb_activate(tls_end: usize, _tls_len: usize) { + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open( + "thisproc:current/regs/env", + syscall::O_CLOEXEC | syscall::O_RDWR, + ) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); + + env.gsbase = tls_end as u32; + + let _ = syscall::write(file, &env).expect_notls("failed to write gsbase"); + + let _ = syscall::close(file); +} + +/// OS and architecture specific code to activate TLS - Redox x86_64 +#[cfg(target_arch = "x86_64")] +pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) { + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open( + "thisproc:current/regs/env", + syscall::O_CLOEXEC | syscall::O_RDWR, + ) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); + + env.fsbase = tls_end_and_tcb_start as u64; + + let _ = syscall::write(file, &env).expect_notls("failed to write fsbase"); + + let _ = syscall::close(file); +} + +/// Initialize redox-rt in situations where relibc is not used +pub fn initialize_freestanding() { + // TODO: TLS + let page = unsafe { + &mut *(syscall::fmap(!0, &syscall::Map { + offset: 0, + size: syscall::PAGE_SIZE, + flags: syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE | syscall::MapFlags::MAP_PRIVATE, + address: 0, + }).unwrap() as *mut Tcb) + }; + page.tcb_ptr = page; + page.tcb_len = syscall::PAGE_SIZE; + page.tls_end = (page as *mut Tcb).cast(); + + unsafe { + tcb_activate(page as *mut Tcb as usize, 0) + } +} diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index d805f4cf3efc39a69d0a24c424e6962ddd8101f7..f1dbf58baa700a76b0b7d29bbec37def1f0bb4fe 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; use syscall::{Error, IntRegisters, Result, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH}; -use crate::arch::*; +use crate::{arch::*, Tcb}; use crate::sync::Mutex; #[cfg(target_arch = "x86_64")] @@ -160,24 +160,18 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction todo!() } -extern "C" { - pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; -} fn current_sigctl() -> &'static Sigcontrol { - unsafe { __relibc_internal_get_sigcontrol_addr() } + &unsafe { Tcb::current() }.unwrap().os_specific.control } pub struct TmpDisableSignalsGuard { _inner: () } -#[thread_local] -static TMP_DISABLE_SIGNALS_DEPTH: Cell<u64> = Cell::new(0); - pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { unsafe { - let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + let ctl = current_sigctl().control_flags.get(); ctl.write_volatile(ctl.read_volatile() | syscall::flag::INHIBIT_DELIVERY); // TODO: fence? - TMP_DISABLE_SIGNALS_DEPTH.set(TMP_DISABLE_SIGNALS_DEPTH.get() + 1); + Tcb::current().unwrap().os_specific.arch.disable_signals_depth += 1; } TmpDisableSignalsGuard { _inner: () } @@ -185,11 +179,11 @@ pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { impl Drop for TmpDisableSignalsGuard { fn drop(&mut self) { unsafe { - let old = TMP_DISABLE_SIGNALS_DEPTH.get(); - TMP_DISABLE_SIGNALS_DEPTH.set(old - 1); + let depth = &mut Tcb::current().unwrap().os_specific.arch.disable_signals_depth; + *depth -= 1; - if old == 1 { - let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get(); + if *depth == 0 { + let ctl = current_sigctl().control_flags.get(); ctl.write_volatile(ctl.read_volatile() & !syscall::flag::INHIBIT_DELIVERY); } } diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 809dad7ebd4e5d18aed04d30792e6cfc3df944b8..db559cb886b0998f750e17b051bba5ca510c4dc3 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -22,47 +22,14 @@ pub mod linker; pub mod start; pub mod tcb; +pub use generic_rt::{panic_notls, ExpectTlsFree}; + static mut STATIC_TCB_MASTER: Master = Master { ptr: ptr::null_mut(), len: 0, offset: 0, }; -fn panic_notls(msg: impl core::fmt::Display) -> ! { - eprintln!("panicked in ld.so: {}", msg); - - core::intrinsics::abort(); -} - -pub trait ExpectTlsFree { - type Unwrapped; - - fn expect_notls(self, msg: &str) -> Self::Unwrapped; -} -impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Ok(t) => t, - Err(err) => panic_notls(format_args!( - "{}: expect failed for Result with err: {:?}", - msg, err - )), - } - } -} -impl<T> ExpectTlsFree for Option<T> { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Some(t) => t, - None => panic_notls(format_args!("{}: expect failed for Option", msg)), - } - } -} - #[inline(never)] pub fn static_init(sp: &'static Stack) { let mut phdr_opt = None; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index b2176b69896edf194e2da6f7e90dc516ce3d95e6..ae1b9eaf4c025ed2484c6cbe0a064cc95f866521 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -223,56 +223,9 @@ impl Tcb { syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end); } - /// OS and architecture specific code to activate TLS - Redox aarch64 - #[cfg(all(target_os = "redox", target_arch = "aarch64"))] + #[cfg(all(target_os = "redox"))] unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) { - // Uses ABI page - let abi_ptr = tls_end - tls_len - 16; - ptr::write(abi_ptr as *mut usize, tls_end); - asm!( - "msr tpidr_el0, {}", - in(reg) abi_ptr, - ); - } - - /// OS and architecture specific code to activate TLS - Redox x86 - #[cfg(all(target_os = "redox", target_arch = "x86"))] - unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { - let mut env = syscall::EnvRegisters::default(); - - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); - - let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); - - env.gsbase = tls_end as u32; - - let _ = syscall::write(file, &env).expect_notls("failed to write gsbase"); - - let _ = syscall::close(file); - } - - /// OS and architecture specific code to activate TLS - Redox x86_64 - #[cfg(all(target_os = "redox", target_arch = "x86_64"))] - unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { - let mut env = syscall::EnvRegisters::default(); - - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); - - let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); - - env.fsbase = tls_end as u64; - - let _ = syscall::write(file, &env).expect_notls("failed to write fsbase"); - - let _ = syscall::close(file); + redox_rt::tcb_activate(tls_end, tls_len) } }