Browse Source

Hacks to support aarch64 static TLS

Jeremy Soller 2 years ago
parent
commit
c59b94d102
1 changed files with 33 additions and 31 deletions
  1. 33 31
      src/ld_so/tcb.rs

+ 33 - 31
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");