use abi::{ error::Error, mem::{MappingFlags, MappingSource}, }; use super::{TlsImage, TlsInfo}; // Variant II TLS layout: // // ... [ MODULE ] [ MODULE ] [ MODULE ] [ TCB ] // | | | | // | | | | // off3 off2 off1 tp /// Creates a new TLS image in the process memory, copying data from the TLS master copy (if any). /// Returns the resulting thread pointer. pub fn clone_tls(image: &TlsImage) -> Result { // Basically, the layout is: // * align(image.full_size) below the TP // * tcb_size starting with the TP // Reserve two words for the TCB to be consistent with Variant I let tcb_size = size_of::() * 2; if !image.align.is_power_of_two() { panic!("TLS layout not aligned to a power of two: {}", image.align); } if image.align > 0x1000 { todo!("Cannot yet handle TLS block alignmnent larger than page size") } let align = image.align; let aligned_size = (image.full_size + tcb_size + align - 1) & !(align - 1); let page_aligned_size = (aligned_size + 0xFFF) & !0xFFF; let base = unsafe { crate::sys::map_memory( None, page_aligned_size, MappingFlags::WRITE, &MappingSource::Anonymous, ) }?; let ptr = core::ptr::with_exposed_provenance_mut::(base); let module_data = unsafe { core::slice::from_raw_parts_mut(ptr, image.full_size) }; let tcb = unsafe { core::slice::from_raw_parts_mut(ptr.add(image.full_size), tcb_size) }; // Clone the Master Copy, if any let data_size = if let Some(master_copy) = image.master_copy { let source = unsafe { master_copy.as_ref() }; module_data[..source.len()].copy_from_slice(source); source.len() } else { 0 }; // Zero the rest module_data[data_size..image.full_size].fill(0); // Place the self-pointer to point at the TP itself let tp = base + image.full_size; assert_eq!( tp % size_of::(), 0, "TLS self-pointer should at least be word-aligned" ); tcb[..size_of::()].copy_from_slice(&tp.to_ne_bytes()); // Zero the TCB after the self-pointer tcb[size_of::()..].fill(0); crate::debug_trace!("TLS: base={:#x}, tp={:#x}", base, tp); Ok(TlsInfo { base, tp, module0_offset: None, }) // Ok((base, tp)) } // In Variant II, the TP points directly at the TCB start pub(super) fn get_tcb_raw(tp: usize) -> *mut u8 { core::ptr::with_exposed_provenance_mut(tp) }