proc: better TLS handling

This commit is contained in:
Mark Poliakov 2024-11-01 18:44:14 +02:00
parent ce2de4bf9d
commit 2d9cc793e0
3 changed files with 62 additions and 66 deletions

View File

@ -13,6 +13,7 @@ use libk_mm::{
pointer::{PhysicalRef, PhysicalRefMut},
process::{ProcessAddressSpace, VirtualRangeBacking},
table::MapAttributes,
PageBox,
};
use libk_util::io::{Read, Seek};
use yggdrasil_abi::{error::Error, io::SeekFrom, path::PathBuf};
@ -20,6 +21,7 @@ use yggdrasil_abi::{error::Error, io::SeekFrom, path::PathBuf};
use crate::{
random,
task::{
mem::ForeignPointer,
process::ProcessImage,
types::{ProcessTlsInfo, ProcessTlsLayout},
},
@ -233,34 +235,52 @@ pub fn clone_tls(space: &ProcessAddressSpace, image: &ProcessImage) -> Result<us
return Ok(0);
};
assert_ne!(tls.master_copy_base, 0);
assert_ne!(tls.layout.mem_size, 0);
assert_ne!(tls.layout.full_size, 0);
let aligned_size = (tls.layout.full_size + 0xFFF) & !0xFFF;
let address = space.allocate(
None,
0x1000,
aligned_size,
VirtualRangeBacking::anonymous(),
MapAttributes::USER_READ | MapAttributes::USER_WRITE | MapAttributes::NON_GLOBAL,
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL,
)?;
let src_phys = space.translate(tls.master_copy_base)?;
let dst_phys = space.translate(address)?;
// Copy data
unsafe {
let src =
PhysicalRef::<u8>::map_slice(src_phys.add(tls.layout.data_offset), tls.layout.mem_size);
let mut dst =
PhysicalRefMut::map_slice(dst_phys.add(tls.layout.data_offset), tls.layout.mem_size);
dst.copy_from_slice(&src);
// Copy master image data
if tls.layout.data_size > 0 {
let master_copy = tls.master_copy.as_ref().unwrap();
load_bytes(
space,
address + tls.layout.data_offset,
tls.layout.data_size,
|off, mut data| {
let len = data.len();
data.copy_from_slice(&master_copy[off..off + len]);
Ok(())
},
)?;
}
// Setup self-pointer
unsafe {
let mut dst = PhysicalRefMut::<usize>::map(dst_phys.add(tls.layout.ptr_offset));
// Zero zeroed data
if tls.layout.mem_size > tls.layout.data_size {
load_bytes(
space,
address + tls.layout.data_offset + tls.layout.data_size,
tls.layout.mem_size - tls.layout.data_size,
|_, mut data| {
data.fill(0);
Ok(())
},
)?;
}
*dst = address + tls.layout.ptr_offset;
// Zero slots and setup self-pointer
unsafe {
let slots: *mut usize = core::ptr::without_provenance_mut(address + tls.layout.slot_offset);
slots.try_write_foreign_volatile(space, 0)?;
slots.add(1).try_write_foreign_volatile(space, 0)?;
let self_ptr: *mut usize =
core::ptr::without_provenance_mut(address + tls.layout.ptr_offset);
self_ptr.try_write_foreign_volatile(space, address + tls.layout.ptr_offset)?;
}
Ok(address + tls.layout.ptr_offset)
@ -401,43 +421,20 @@ fn handle_tls<F: Read + Seek>(
tls_segment.p_filesz as _,
tls_segment.p_memsz as _,
);
let data_offset = layout.data_offset;
let data_size = layout.data_size;
let mem_size = layout.mem_size;
let aligned_size = (layout.full_size + 0xFFF) & !0xFFF;
let attrs =
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL;
let master_copy_base =
space.allocate(None, aligned_size, VirtualRangeBacking::anonymous(), attrs)?;
assert!(layout.mem_size <= layout.full_size);
if data_size > 0 {
load_bytes(
space,
master_copy_base + data_offset,
data_size,
|off, mut dst| {
file.file
.seek(SeekFrom::Start(tls_segment.p_offset + off as u64))?;
file.file.read_exact(dst.deref_mut())
},
)?;
}
if mem_size > data_size {
load_bytes(
space,
master_copy_base + data_offset + data_size,
mem_size - data_size,
|_, mut dst| {
dst.fill(0);
Ok(())
},
)?;
}
let master_copy = if layout.data_size > 0 {
let mut data = PageBox::new_slice(0, layout.data_size)?;
file.file.seek(SeekFrom::Start(tls_segment.p_offset))?;
file.file.read_exact(&mut data)?;
Some(Arc::new(data))
} else {
None
};
Ok(Some(ProcessTlsInfo {
master_copy_base,
master_copy,
layout,
}))
} else {

View File

@ -1,6 +1,8 @@
use core::{alloc::Layout, mem::size_of};
use libk_mm::{address::Virtualize, process::ProcessAddressSpace};
use libk_mm::{
address::Virtualize, pointer::PhysicalRef, process::ProcessAddressSpace, table::EntryLevelExt,
};
use yggdrasil_abi::error::Error;
// XXX

View File

@ -1,9 +1,12 @@
use alloc::sync::Arc;
use core::{
fmt,
range::Range,
sync::atomic::{AtomicU32, AtomicU64, Ordering},
};
use atomic_enum::atomic_enum;
use libk_mm::PageBox;
use yggdrasil_abi::process::ProcessId;
pub trait AllocateProcessId {
@ -52,8 +55,8 @@ pub enum ThreadId {
/// Describes Thread-Local Storage of a process
#[derive(Clone, Debug)]
pub struct ProcessTlsInfo {
/// Location of the TLS master copy within the process's memory
pub master_copy_base: usize,
/// Master copy of the TLS
pub master_copy: Option<Arc<PageBox<[u8]>>>,
/// Layout of the TLS
pub layout: ProcessTlsLayout,
}
@ -61,18 +64,12 @@ pub struct ProcessTlsInfo {
/// Describes TLS layout for a program image
#[derive(Clone, Debug)]
pub struct ProcessTlsLayout {
/// Data offset from the TLS base
pub data_offset: usize,
/// struct uthread offset from the TLS base
pub uthread_offset: usize,
/// Pointer offset from the TLS base. The pointer is passed to the userspace
pub ptr_offset: usize,
/// Data size of the TLS segment
pub data_offset: usize,
pub data_size: usize,
/// Memory size of the TLS segment (mem_size >= data_size)
pub mem_size: usize,
pub slot_offset: usize,
/// Overall allocation size of the TLS data
pub full_size: usize,
}
@ -170,8 +167,8 @@ impl ProcessTlsLayout {
Self {
data_offset: tls_block0_offset + back_size,
uthread_offset: back_size,
ptr_offset: back_size,
slot_offset: 0,
data_size,
mem_size,
@ -200,8 +197,8 @@ impl ProcessTlsLayout {
Self {
data_offset: 0,
uthread_offset: back_size,
ptr_offset: back_size,
slot_offset: back_size + 2 * size_of::<usize>(),
data_size,
mem_size,
@ -222,8 +219,8 @@ impl ProcessTlsLayout {
Self {
data_offset: 0,
uthread_offset: back_size,
ptr_offset: back_size,
slot_offset: back_size + 2 * size_of::<usize>(),
data_size,
mem_size,