86 lines
2.6 KiB
Rust
Raw Normal View History

2024-11-17 23:32:07 +02:00
use abi::{
error::Error,
mem::{MappingFlags, MappingSource},
};
use super::TlsImage;
// 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, tcb_size: usize) -> Result<(usize, usize), Error> {
// Basically, the layout is:
// * align(image.full_size) below the TP
// * tcb_size starting with the TP
// If the caller asked for no TCB to be placed, just reserve two words, the first one
// will be used to put the self-pointer
let tcb_size = if tcb_size < size_of::<usize>() * 2 {
size_of::<usize>() * 2
} else {
(tcb_size + size_of::<usize>() - 1) & !(size_of::<usize>() - 1)
};
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::<u8>(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::<usize>(),
0,
"TLS self-pointer should at least be word-aligned"
);
tcb[..size_of::<usize>()].copy_from_slice(&tp.to_ne_bytes());
// Zero the TCB after the self-pointer
tcb[size_of::<usize>()..].fill(0);
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)
}