1 use alloc::vec::Vec; 2 use core::{mem, ptr, slice}; 3 use goblin::error::{Error, Result}; 4 5 use crate::{header::sys_mman, ld_so::linker::Linker, sync::mutex::Mutex}; 6 7 use super::PAGE_SIZE; 8 9 #[repr(C)] 10 #[derive(Debug)] 11 pub struct Master { 12 /// Pointer to initial data 13 pub ptr: *const u8, 14 /// Length of initial data in bytes 15 pub len: usize, 16 /// Offset in TLS to copy initial data to 17 pub offset: usize, 18 } 19 20 impl Master { 21 /// The initial data for this TLS region 22 pub unsafe fn data(&self) -> &'static [u8] { 23 slice::from_raw_parts(self.ptr, self.len) 24 } 25 } 26 27 #[derive(Debug)] 28 #[repr(C)] 29 pub struct Tcb { 30 /// Pointer to the end of static TLS. Must be the first member 31 pub tls_end: *mut u8, 32 /// Size of the memory allocated for the static TLS in bytes (multiple of PAGE_SIZE) 33 pub tls_len: usize, 34 /// Pointer to this structure 35 pub tcb_ptr: *mut Tcb, 36 /// Size of the memory allocated for this structure in bytes (should be PAGE_SIZE) 37 pub tcb_len: usize, 38 /// Pointer to a list of initial TLS data 39 pub masters_ptr: *mut Master, 40 /// Size of the masters list in bytes (multiple of mem::size_of::<Master>()) 41 pub masters_len: usize, 42 /// Index of last copied Master 43 pub last_master_copied: usize, 44 /// Pointer to dynamic linker 45 pub linker_ptr: *const Mutex<Linker>, 46 /// pointer to rust memory allocator structure 47 pub mspace: usize, 48 } 49 50 impl Tcb { 51 /// Create a new TCB 52 pub unsafe fn new(size: usize) -> Result<&'static mut Self> { 53 let (tls, tcb_page) = Self::os_new(round_up(size, PAGE_SIZE))?; 54 55 let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self; 56 trace!("New TCB: {:p}", tcb_ptr); 57 ptr::write( 58 tcb_ptr, 59 Self { 60 tls_end: tls.as_mut_ptr().add(tls.len()), 61 tls_len: tls.len(), 62 tcb_ptr, 63 tcb_len: tcb_page.len(), 64 masters_ptr: ptr::null_mut(), 65 masters_len: 0, 66 last_master_copied: 0, 67 linker_ptr: ptr::null(), 68 mspace: 0, 69 }, 70 ); 71 72 Ok(&mut *tcb_ptr) 73 } 74 75 /// Get the current TCB 76 pub unsafe fn current() -> Option<&'static mut Self> { 77 let tcb_ptr = Self::arch_read(offset_of!(Self, tcb_ptr)) as *mut Self; 78 let tcb_len = Self::arch_read(offset_of!(Self, tcb_len)); 79 if tcb_ptr.is_null() || tcb_len < mem::size_of::<Self>() { 80 None 81 } else { 82 Some(&mut *tcb_ptr) 83 } 84 } 85 86 /// A slice for all of the TLS data 87 pub unsafe fn tls(&self) -> Option<&'static mut [u8]> { 88 if self.tls_end.is_null() || self.tls_len == 0 { 89 None 90 } else { 91 Some(slice::from_raw_parts_mut( 92 self.tls_end.offset(-(self.tls_len as isize)), 93 self.tls_len, 94 )) 95 } 96 } 97 98 /// The initial images for TLS 99 pub unsafe fn masters(&self) -> Option<&'static mut [Master]> { 100 if self.masters_ptr.is_null() || self.masters_len == 0 { 101 None 102 } else { 103 Some(slice::from_raw_parts_mut( 104 self.masters_ptr, 105 self.masters_len / mem::size_of::<Master>(), 106 )) 107 } 108 } 109 110 /// Copy data from masters 111 pub unsafe fn copy_masters(&mut self) -> Result<()> { 112 //TODO: Complain if masters or tls exist without the other 113 if let Some(tls) = self.tls() { 114 if let Some(masters) = self.masters() { 115 for (i, master) in masters 116 .iter() 117 .skip(self.last_master_copied) 118 .filter(|m| m.len > 0) 119 .enumerate() 120 { 121 let range = 122 self.tls_len - master.offset..self.tls_len - master.offset + master.len; 123 if let Some(tls_data) = tls.get_mut(range) { 124 let data = master.data(); 125 trace!( 126 "tls master {}: {:p}, {:#x}: {:p}, {:#x}", 127 i, 128 data.as_ptr(), 129 data.len(), 130 tls_data.as_mut_ptr(), 131 tls_data.len() 132 ); 133 tls_data.copy_from_slice(data); 134 } else { 135 return Err(Error::Malformed(format!("failed to copy tls master {}", i))); 136 } 137 } 138 self.last_master_copied = masters.len(); 139 } 140 } 141 142 Ok(()) 143 } 144 145 /// The initial images for TLS 146 pub unsafe fn append_masters(&mut self, mut new_masters: Vec<Master>) { 147 if self.masters_ptr.is_null() { 148 self.masters_ptr = new_masters.as_mut_ptr(); 149 self.masters_len = new_masters.len() * mem::size_of::<Master>(); 150 mem::forget(new_masters); 151 } else { 152 let len = self.masters_len / mem::size_of::<Master>(); 153 let mut masters = Vec::from_raw_parts(self.masters_ptr, len, len); 154 masters.extend(new_masters.into_iter()); 155 self.masters_ptr = masters.as_mut_ptr(); 156 self.masters_len = masters.len() * mem::size_of::<Master>(); 157 mem::forget(masters); 158 } 159 } 160 161 /// Activate TLS 162 pub unsafe fn activate(&mut self) { 163 Self::os_arch_activate(self.tcb_ptr as usize); 164 } 165 166 /// Mapping with correct flags for TCB and TLS 167 unsafe fn map(size: usize) -> Result<&'static mut [u8]> { 168 let ptr = sys_mman::mmap( 169 ptr::null_mut(), 170 size, 171 sys_mman::PROT_READ | sys_mman::PROT_WRITE, 172 sys_mman::MAP_ANONYMOUS | sys_mman::MAP_PRIVATE, 173 -1, 174 0, 175 ); 176 if ptr as usize == !0 177 /* MAP_FAILED */ 178 { 179 return Err(Error::Malformed(format!("failed to map tls"))); 180 } 181 ptr::write_bytes(ptr as *mut u8, 0, size); 182 Ok(slice::from_raw_parts_mut(ptr as *mut u8, size)) 183 } 184 185 /// OS specific code to create a new TLS and TCB - Linux 186 #[cfg(target_os = "linux")] 187 unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { 188 let tls_tcb = Self::map(size + PAGE_SIZE)?; 189 Ok(tls_tcb.split_at_mut(size)) 190 } 191 192 /// OS specific code to create a new TLS and TCB - Redox 193 #[cfg(target_os = "redox")] 194 unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { 195 use crate::header::unistd; 196 //TODO: better method of finding fs offset 197 let pid = unistd::getpid(); 198 let tcb_addr = 0xB000_0000 + pid as usize * PAGE_SIZE; 199 let tls = Self::map(size)?; 200 Ok(( 201 tls, 202 //TODO: Consider allocating TCB as part of TLS 203 slice::from_raw_parts_mut(tcb_addr as *mut u8, PAGE_SIZE), 204 )) 205 } 206 207 /// Architecture specific code to read a usize from the TCB - x86_64 208 #[inline(always)] 209 #[cfg(target_arch = "x86_64")] 210 unsafe fn arch_read(offset: usize) -> usize { 211 let value; 212 llvm_asm!(" 213 mov rax, fs:[rdi] 214 " 215 : "={rax}"(value) 216 : "{rdi}"(offset) 217 : 218 : "intel" 219 ); 220 value 221 } 222 223 /// OS and architecture specific code to activate TLS - Linux x86_64 224 #[cfg(all(target_os = "linux", target_arch = "x86_64"))] 225 unsafe fn os_arch_activate(tp: usize) { 226 const ARCH_SET_FS: usize = 0x1002; 227 syscall!(ARCH_PRCTL, ARCH_SET_FS, tp); 228 } 229 230 /// OS and architecture specific code to activate TLS - Linux x86_64 231 #[cfg(all(target_os = "redox", target_arch = "x86_64"))] 232 unsafe fn os_arch_activate(tp: usize) { 233 //TODO: Consider setting FS offset to TCB pointer 234 } 235 } 236 237 pub fn round_up(value: usize, alignment: usize) -> usize { 238 return (value + alignment - 1) & (!(alignment - 1)); 239 } 240