From 2d9cc793e076742df8570c3e76c0146d5074b850 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 1 Nov 2024 18:44:14 +0200 Subject: [PATCH] proc: better TLS handling --- kernel/libk/src/task/binary/elf.rs | 101 ++++++++++++++--------------- kernel/libk/src/task/mem.rs | 4 +- kernel/libk/src/task/types.rs | 23 +++---- 3 files changed, 62 insertions(+), 66 deletions(-) diff --git a/kernel/libk/src/task/binary/elf.rs b/kernel/libk/src/task/binary/elf.rs index 34ef2403..b9003032 100644 --- a/kernel/libk/src/task/binary/elf.rs +++ b/kernel/libk/src/task/binary/elf.rs @@ -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::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::::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( 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 { diff --git a/kernel/libk/src/task/mem.rs b/kernel/libk/src/task/mem.rs index 222cd351..9493fdef 100644 --- a/kernel/libk/src/task/mem.rs +++ b/kernel/libk/src/task/mem.rs @@ -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 diff --git a/kernel/libk/src/task/types.rs b/kernel/libk/src/task/types.rs index b7ac730a..3075b13b 100644 --- a/kernel/libk/src/task/types.rs +++ b/kernel/libk/src/task/types.rs @@ -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>>, /// 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::(), 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::(), data_size, mem_size,