From c59b94d1021a9c7c9a41bb073b77b1a03a6b258f Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Thu, 25 Aug 2022 19:03:49 -0600 Subject: [PATCH] Hacks to support aarch64 static TLS --- src/ld_so/tcb.rs | 64 +++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 404c84784..7b7f1f230 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -55,7 +55,7 @@ impl Tcb { /// Create a new TCB pub unsafe fn new(size: usize) -> Result<&'static mut Self> { let page_size = Sys::getpagesize(); - let (tls, tcb_page) = Self::os_new(round_up(size, page_size))?; + let (abi_page, tls, tcb_page) = Self::os_new(round_up(size, page_size))?; let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self; trace!("New TCB: {:p}", tcb_ptr); @@ -123,8 +123,14 @@ impl Tcb { .filter(|m| m.len > 0) .enumerate() { - let range = - self.tls_len - master.offset..self.tls_len - master.offset + master.len; + let range = if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // x86 TLS layout is backwards + self.tls_len - master.offset..self.tls_len - master.offset + master.len + } else { + //TODO: fix aarch64 TLS layout when there is more than one master + assert_eq!(i, 0, "aarch64 TLS layout only supports one master"); + 0..master.len + }; if let Some(tls_data) = tls.get_mut(range) { let data = master.data(); trace!( @@ -165,7 +171,7 @@ impl Tcb { /// Activate TLS pub unsafe fn activate(&mut self) { - Self::os_arch_activate(self.tcb_ptr as usize); + Self::os_arch_activate(self.tls_end as usize, self.tls_len); } /// Mapping with correct flags for TCB and TLS @@ -189,23 +195,26 @@ impl Tcb { /// OS specific code to create a new TLS and TCB - Linux and Redox #[cfg(any(target_os = "linux", target_os = "redox"))] - unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { + unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8], &'static mut [u8])> { let page_size = Sys::getpagesize(); - let tls_tcb = Self::map(size + page_size)?; - Ok(tls_tcb.split_at_mut(size)) + let abi_tls_tcb = Self::map(page_size + size + page_size)?; + let (abi, tls_tcb) = abi_tls_tcb.split_at_mut(page_size); + let (tls, tcb) = tls_tcb.split_at_mut(size); + Ok((abi, tls, tcb)) } /// Architecture specific code to read a usize from the TCB - aarch64 #[inline(always)] #[cfg(target_arch = "aarch64")] unsafe fn arch_read(offset: usize) -> usize { - let tp: usize; + let abi_ptr: usize; asm!( "mrs {}, tpidr_el0", - out(reg) tp, + out(reg) abi_ptr, ); - *((tp + offset) as *const usize) + let tcb_ptr = *(abi_ptr as *const usize); + *((tcb_ptr + offset) as *const usize) } /// Architecture specific code to read a usize from the TCB - x86 @@ -240,33 +249,26 @@ impl Tcb { /// OS and architecture specific code to activate TLS - Linux x86_64 #[cfg(all(target_os = "linux", target_arch = "x86_64"))] - unsafe fn os_arch_activate(tp: usize) { + unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { const ARCH_SET_FS: usize = 0x1002; - syscall!(ARCH_PRCTL, ARCH_SET_FS, tp); + 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"))] - unsafe fn os_arch_activate(tp: 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 thread pointer"); - - env.tpidr_el0 = tp; - - let _ = syscall::write(file, &env) - .expect_notls("failed to write thread pointer"); - - let _ = syscall::close(file); + 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(tp: usize) { + 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) @@ -275,7 +277,7 @@ impl Tcb { let _ = syscall::read(file, &mut env) .expect_notls("failed to read gsbase"); - env.gsbase = tp as u32; + env.gsbase = tls_end as u32; let _ = syscall::write(file, &env) .expect_notls("failed to write gsbase"); @@ -285,7 +287,7 @@ impl Tcb { /// 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(tp: usize) { + 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) @@ -294,7 +296,7 @@ impl Tcb { let _ = syscall::read(file, &mut env) .expect_notls("failed to read fsbase"); - env.fsbase = tp as u64; + env.fsbase = tls_end as u64; let _ = syscall::write(file, &env) .expect_notls("failed to write fsbase"); -- GitLab