Ver Fonte

tls: rework of arch's UserTLS design

Separate old UserTLS into UserTLS and UserTLSDescriptor.

UserTLS is for threads to hold infomation about its storage. Descriptors
are used in clone syscalls.

Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf há 1 mês atrás
pai
commit
922324322b

+ 3 - 2
Cargo.lock

@@ -75,9 +75,9 @@ dependencies = [
 
 [[package]]
 name = "cfg-if"
-version = "1.0.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "critical-section"
@@ -164,6 +164,7 @@ dependencies = [
  "atomic_unique_refcell",
  "bitflags",
  "buddy_allocator",
+ "cfg-if",
  "eonix_hal",
  "eonix_log",
  "eonix_macros",

+ 1 - 0
Cargo.toml

@@ -43,6 +43,7 @@ futures = { version = "0.3.31", features = [
     "async-await",
 ], default-features = false }
 static_assertions = "1.1.0"
+cfg-if = "1.0.4"
 
 [target.'cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))'.dependencies]
 virtio-drivers = { version = "0.11.0" }

+ 0 - 17
crates/eonix_hal/src/arch/riscv64/cpu.rs

@@ -27,22 +27,11 @@ static DEFAULT_TRAP_CONTEXT: MaybeUninit<TrapContext> = MaybeUninit::uninit();
 #[eonix_percpu::define_percpu]
 static LOCAL_CPU: LazyLock<CPU> = LazyLock::new(|| CPU::new(CPUID.get()));
 
-#[derive(Debug, Clone)]
-pub enum UserTLS {
-    Base(u64),
-}
-
 /// RISC-V Hart
 pub struct CPU {
     pub(crate) interrupt: InterruptControl,
 }
 
-impl UserTLS {
-    pub fn new(base: u64) -> Self {
-        Self::Base(base)
-    }
-}
-
 impl CPU {
     fn new(cpuid: usize) -> Self {
         Self {
@@ -66,12 +55,6 @@ impl CPU {
         sscratch::write(DEFAULT_TRAP_CONTEXT.as_ptr() as usize);
     }
 
-    pub unsafe fn load_interrupt_stack(self: Pin<&mut Self>, sp: u64) {}
-
-    pub fn set_tls32(self: Pin<&mut Self>, _user_tls: &UserTLS) {
-        // nothing
-    }
-
     pub fn local() -> PreemptGuard<Pin<&'static mut Self>> {
         unsafe {
             // SAFETY: We pass the reference into a `PreemptGuard`, which ensures

+ 1 - 1
crates/eonix_hal/src/lib.rs

@@ -19,7 +19,7 @@ pub mod fpu {
 }
 
 pub mod processor {
-    pub use crate::arch::cpu::{halt, UserTLS, CPU, CPU_COUNT};
+    pub use crate::arch::cpu::{halt, CPU, CPU_COUNT};
 }
 
 /// Re-export the arch module for use in other crates

+ 1 - 2
crates/posix_types/src/syscall_no/loongarch64.rs

@@ -136,7 +136,7 @@ pub const SYS_RT_SIGSUSPEND: usize = 133;
 pub const SYS_RT_SIGACTION: usize = 134;
 pub const SYS_RT_SIGPROCMASK: usize = 135;
 pub const SYS_RT_SIGPENDING: usize = 136;
-pub const SYS_RT_SIGTIMEDWAIT_TIME32: usize = 137;
+pub const SYS_RT_SIGTIMEDWAIT: usize = 137;
 pub const SYS_RT_SIGQUEUEINFO: usize = 138;
 pub const SYS_RT_SIGRETURN: usize = 139;
 pub const SYS_SETPRIORITY: usize = 140;
@@ -295,7 +295,6 @@ pub const SYS_RECVMMSG: usize = 417;
 pub const SYS_MQ_TIMEDSEND: usize = 418;
 pub const SYS_MQ_TIMEDRECEIVE: usize = 419;
 pub const SYS_SEMTIMEDOP: usize = 420;
-pub const SYS_RT_SIGTIMEDWAIT: usize = 421;
 pub const SYS_FUTEX: usize = 422;
 pub const SYS_SCHED_RR_GET_INTERVAL: usize = 423;
 pub const SYS_PIDFD_SEND_SIGNAL: usize = 424;

+ 1 - 1
crates/posix_types/src/syscall_no/riscv64.rs

@@ -136,7 +136,7 @@ pub const SYS_RT_SIGSUSPEND: usize = 133;
 pub const SYS_RT_SIGACTION: usize = 134;
 pub const SYS_RT_SIGPROCMASK: usize = 135;
 pub const SYS_RT_SIGPENDING: usize = 136;
-pub const SYS_RT_SIGTIMEDWAIT_TIME32: usize = 137;
+pub const SYS_RT_SIGTIMEDWAIT: usize = 137;
 pub const SYS_RT_SIGQUEUEINFO: usize = 138;
 pub const SYS_RT_SIGRETURN: usize = 139;
 pub const SYS_SETPRIORITY: usize = 140;

+ 7 - 5
src/kernel/interrupt.rs

@@ -1,15 +1,17 @@
-use super::mem::handle_kernel_page_fault;
-use super::task::block_on;
-use super::timer::timer_interrupt;
-use crate::kernel::constants::EINVAL;
-use crate::prelude::*;
 use alloc::sync::Arc;
+
 use eonix_hal::traits::fault::Fault;
 use eonix_hal::traits::trap::{RawTrapContext, TrapType};
 use eonix_hal::trap::TrapContext;
 use eonix_mm::address::{Addr as _, VAddr};
 use eonix_sync::SpinIrq as _;
 
+use super::mem::handle_kernel_page_fault;
+use super::task::block_on;
+use super::timer::timer_interrupt;
+use crate::kernel::constants::EINVAL;
+use crate::prelude::*;
+
 static IRQ_HANDLERS: Spin<[Vec<Arc<dyn Fn() + Send + Sync>>; 16]> =
     Spin::new([const { Vec::new() }; 16]);
 

+ 10 - 8
src/kernel/pcie/init.rs

@@ -1,13 +1,14 @@
-use super::{
-    device::{PCIDevice, SegmentGroup, PCIE_DEVICES},
-    error::PciError,
-};
-use crate::kernel::{mem::PhysAccess as _, pcie::device::PciMemoryAllocator};
-use acpi::{AcpiHandler, PhysicalMapping};
 use alloc::collections::btree_map::Entry;
 use alloc::vec;
+
+use acpi::{AcpiHandler, PhysicalMapping};
 use eonix_log::println_trace;
-use eonix_mm::address::PAddr;
+use eonix_mm::address::{PAddr, PRange};
+
+use super::device::{PCIDevice, SegmentGroup, PCIE_DEVICES};
+use super::error::PciError;
+use crate::kernel::mem::PhysAccess as _;
+use crate::kernel::pcie::device::PciMemoryAllocator;
 
 #[derive(Clone)]
 struct AcpiHandlerImpl;
@@ -67,10 +68,11 @@ pub fn init_pcie() -> Result<(), PciError> {
 
     #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))]
     {
-        use crate::kernel::constants::{EINVAL, EIO, ENOENT};
         use eonix_hal::arch_exported::fdt::FDT;
         use eonix_mm::address::PRange;
 
+        use crate::kernel::constants::{EINVAL, EIO, ENOENT};
+
         let pcie_node = FDT
             .find_compatible(&["pci-host-ecam-generic"])
             .ok_or(ENOENT)?;

+ 37 - 30
src/kernel/syscall/file_rw.rs

@@ -1,33 +1,31 @@
+use alloc::sync::Arc;
+use core::time::Duration;
+
+use posix_types::ctypes::{Long, PtrT};
+use posix_types::namei::RenameFlags;
+use posix_types::open::{AtFlags, OpenFlags};
+use posix_types::poll::FDSet;
+use posix_types::signal::{SigSet, Signal};
+use posix_types::stat::{Stat, StatX, TimeSpec};
+use posix_types::syscall_no::*;
+
 use super::{FromSyscallArg, User};
-use crate::io::IntoStream;
+use crate::io::{Buffer, BufferFill, IntoStream};
 use crate::kernel::constants::{
     EBADF, EFAULT, EINVAL, ENOENT, ENOSYS, ENOTDIR, SEEK_CUR, SEEK_END, SEEK_SET,
 };
 use crate::kernel::syscall::UserMut;
 use crate::kernel::task::Thread;
 use crate::kernel::timer::sleep;
+use crate::kernel::user::{
+    CheckedUserPointer, UserBuffer, UserPointer, UserPointerMut, UserString,
+};
+use crate::kernel::vfs::dentry::Dentry;
 use crate::kernel::vfs::filearray::FD;
 use crate::kernel::vfs::types::{DeviceId, Mode};
 use crate::kernel::vfs::{PollEvent, SeekOption};
-use crate::{
-    io::{Buffer, BufferFill},
-    kernel::{
-        user::{CheckedUserPointer, UserBuffer, UserPointer, UserPointerMut, UserString},
-        vfs::dentry::Dentry,
-    },
-    path::Path,
-    prelude::*,
-};
-use alloc::sync::Arc;
-use core::time::Duration;
-use posix_types::ctypes::{Long, PtrT};
-use posix_types::namei::RenameFlags;
-use posix_types::open::{AtFlags, OpenFlags};
-use posix_types::poll::FDSet;
-use posix_types::signal::{SigSet, Signal};
-use posix_types::stat::Stat;
-use posix_types::stat::{StatX, TimeSpec};
-use posix_types::syscall_no::*;
+use crate::path::Path;
+use crate::prelude::*;
 
 impl FromSyscallArg for OpenFlags {
     fn from_arg(value: usize) -> Self {
@@ -128,7 +126,7 @@ async fn openat(dirfd: FD, pathname: User<u8>, flags: OpenFlags, mode: Mode) ->
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_OPEN)]
-async fn open(path: User<u8>, flags: OpenFlags, mode: u32) -> KResult<FD> {
+async fn open(path: User<u8>, flags: OpenFlags, mode: Mode) -> KResult<FD> {
     sys_openat(thread, FD::AT_FDCWD, path, flags, mode).await
 }
 
@@ -145,7 +143,10 @@ async fn dup(fd: FD) -> KResult<FD> {
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_DUP2)]
 async fn dup2(old_fd: FD, new_fd: FD) -> KResult<FD> {
-    thread.files.dup_to(old_fd, new_fd, OpenFlags::empty())
+    thread
+        .files
+        .dup_to(old_fd, new_fd, OpenFlags::empty())
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_DUP3)]
@@ -172,7 +173,13 @@ async fn pipe(pipe_fd: UserMut<[FD; 2]>) -> KResult<()> {
 async fn getdents(fd: FD, buffer: UserMut<u8>, bufsize: usize) -> KResult<usize> {
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
-    thread.files.get(fd).ok_or(EBADF)?.getdents(&mut buffer)?;
+    thread
+        .files
+        .get(fd)
+        .ok_or(EBADF)?
+        .getdents(&mut buffer)
+        .await?;
+
     Ok(buffer.wrote())
 }
 
@@ -264,7 +271,7 @@ async fn mkdirat(dirfd: FD, pathname: User<u8>, mode: Mode) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_MKDIR)]
-async fn mkdir(pathname: User<u8>, mode: u32) -> KResult<()> {
+async fn mkdir(pathname: User<u8>, mode: Mode) -> KResult<()> {
     sys_mkdirat(thread, FD::AT_FDCWD, pathname, mode).await
 }
 
@@ -280,9 +287,9 @@ async fn truncate(pathname: User<u8>, length: usize) -> KResult<()> {
     let path = UserString::new(pathname)?;
     let path = Path::new(path.as_cstr().to_bytes())?;
 
-    let dentry = Dentry::open(&thread.fs_context, path, true)?;
+    let dentry = Dentry::open(&thread.fs_context, path, true).await?;
 
-    dentry.truncate(length)
+    dentry.truncate(length).await
 }
 
 #[eonix_macros::define_syscall(SYS_UNLINKAT)]
@@ -296,7 +303,7 @@ async fn unlinkat(dirfd: FD, pathname: User<u8>) -> KResult<()> {
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_UNLINK)]
 async fn unlink(pathname: User<u8>) -> KResult<()> {
-    sys_unlinkat(thread, FD::AT_FDCWD, pathname)
+    sys_unlinkat(thread, FD::AT_FDCWD, pathname).await
 }
 
 #[eonix_macros::define_syscall(SYS_SYMLINKAT)]
@@ -310,7 +317,7 @@ async fn symlinkat(target: User<u8>, dirfd: FD, linkpath: User<u8>) -> KResult<(
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SYMLINK)]
 async fn symlink(target: User<u8>, linkpath: User<u8>) -> KResult<()> {
-    sys_symlinkat(thread, target, FD::AT_FDCWD, linkpath)
+    sys_symlinkat(thread, target, FD::AT_FDCWD, linkpath).await
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -347,7 +354,7 @@ async fn mknodat(dirfd: FD, pathname: User<u8>, mut mode: Mode, dev: UserDeviceI
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_MKNOD)]
-async fn mknod(pathname: User<u8>, mode: u32, dev: u32) -> KResult<()> {
+async fn mknod(pathname: User<u8>, mode: Mode, dev: UserDeviceId) -> KResult<()> {
     sys_mknodat(thread, FD::AT_FDCWD, pathname, mode, dev).await
 }
 
@@ -389,7 +396,7 @@ async fn lseek(fd: FD, offset: u64, whence: u32) -> KResult<u64> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_LLSEEK)]
-fn llseek(
+async fn llseek(
     fd: FD,
     offset_high: u32,
     offset_low: u32,

+ 54 - 80
src/kernel/syscall/procops.rs

@@ -1,38 +1,37 @@
+use alloc::borrow::ToOwned;
+use alloc::ffi::CString;
+use core::time::Duration;
+
+use bitflags::bitflags;
+use eonix_hal::traits::trap::RawTrapContext;
+use eonix_hal::trap::TrapContext;
+use eonix_mm::address::Addr as _;
+use eonix_sync::AsProof as _;
+use posix_types::ctypes::PtrT;
+use posix_types::signal::{SigAction, SigInfo, SigSet, Signal};
+use posix_types::stat::{TimeSpec, TimeVal};
+use posix_types::syscall_no::*;
+use posix_types::SIGNAL_NOW;
+
 use super::SyscallNoReturn;
 use crate::io::Buffer;
 use crate::kernel::constants::{
-    CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_REALTIME_COARSE, EINVAL, ENOENT, ENOTDIR, ERANGE, ESRCH,
-};
-use crate::kernel::constants::{
-    ENOSYS, PR_GET_NAME, PR_SET_NAME, RLIMIT_STACK, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK,
+    CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_REALTIME_COARSE, EINVAL, ENOENT, ENOSYS, ENOTDIR,
+    ERANGE, ESRCH, PR_GET_NAME, PR_SET_NAME, RLIMIT_STACK, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK,
 };
 use crate::kernel::mem::PageBuffer;
 use crate::kernel::syscall::{User, UserMut};
 use crate::kernel::task::{
-    do_clone, futex_wait, futex_wake, yield_now, FutexFlags, FutexOp, ProcessList, ProgramLoader,
-    RobustListHead, SignalAction, Thread, WaitId, WaitType,
+    do_clone, futex_wait, futex_wake, parse_futexop, yield_now, CloneArgs, FutexFlags, FutexOp,
+    ProcessList, ProgramLoader, RobustListHead, SignalAction, Thread, WaitId, WaitType,
 };
-use crate::kernel::task::{parse_futexop, CloneArgs};
 use crate::kernel::timer::sleep;
-use crate::kernel::user::UserString;
-use crate::kernel::user::{UserPointer, UserPointerMut};
+use crate::kernel::user::{UserBuffer, UserPointer, UserPointerMut, UserString};
+use crate::kernel::vfs::dentry::Dentry;
 use crate::kernel::vfs::types::Permission;
-use crate::kernel::vfs::{self, dentry::Dentry};
+use crate::kernel::vfs::{self};
 use crate::path::Path;
-use crate::{kernel::user::UserBuffer, prelude::*};
-use alloc::borrow::ToOwned;
-use alloc::ffi::CString;
-use bitflags::bitflags;
-use core::time::Duration;
-use eonix_hal::processor::UserTLS;
-use eonix_hal::traits::trap::RawTrapContext;
-use eonix_hal::trap::TrapContext;
-use eonix_mm::address::Addr as _;
-use eonix_sync::AsProof as _;
-use posix_types::ctypes::PtrT;
-use posix_types::signal::{SigAction, SigInfo, SigSet, Signal};
-use posix_types::stat::TimeVal;
-use posix_types::{syscall_no::*, SIGNAL_NOW};
+use crate::prelude::*;
 
 #[repr(C)]
 #[derive(Debug, Clone, Copy)]
@@ -366,7 +365,7 @@ async fn wait4(
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_WAITPID)]
 async fn waitpid(waitpid: i32, arg1: UserMut<u32>, options: u32) -> KResult<u32> {
-    sys_wait4(thread, waitpid, arg1, options, core::ptr::null_mut()).await
+    sys_wait4(thread, waitpid, arg1, options, UserMut::null()).await
 }
 
 #[eonix_macros::define_syscall(SYS_SETSID)]
@@ -493,51 +492,15 @@ async fn gettid() -> KResult<u32> {
     Ok(thread.tid)
 }
 
-pub fn parse_user_tls(arch_tls: usize) -> KResult<UserTLS> {
-    #[cfg(target_arch = "x86_64")]
-    {
-        let desc = arch_tls as *mut posix_types::x86_64::UserDescriptor;
-        let desc_pointer = UserPointerMut::new(desc)?;
-        let mut desc = desc_pointer.read()?;
-
-        // Clear the TLS area if it is not present.
-        if desc.flags.is_read_exec_only() && !desc.flags.is_present() {
-            if desc.limit != 0 && desc.base != 0 {
-                let len = if desc.flags.is_limit_in_pages() {
-                    (desc.limit as usize) << 12
-                } else {
-                    desc.limit as usize
-                };
-
-                CheckedUserPointer::new(desc.base as _, len)?.zero()?;
-            }
-        }
-
-        let (new_tls, entry) =
-            UserTLS::new32(desc.base, desc.limit, desc.flags.is_limit_in_pages());
-        desc.entry = entry;
-        desc_pointer.write(desc)?;
-
-        Ok(new_tls)
-    }
-
-    #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))]
-    {
-        Ok(UserTLS::new(arch_tls as u64))
-    }
-}
-
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SET_THREAD_AREA)]
-async fn set_thread_area(arch_tls: usize) -> KResult<()> {
-    thread.set_user_tls(parse_user_tls(arch_tls)?)?;
+async fn set_thread_area(tls: PtrT) -> KResult<()> {
+    use crate::kernel::task::UserTLSDescriptor;
 
-    // SAFETY: Preemption is disabled on calling `load_thread_area32()`.
-    unsafe {
-        eonix_preempt::disable();
-        thread.load_thread_area32();
-        eonix_preempt::enable();
-    }
+    let tls = UserTLSDescriptor::new(tls)?.read()?;
+
+    thread.set_user_tls(tls)?;
+    thread.activate_tls();
 
     Ok(())
 }
@@ -651,18 +614,14 @@ async fn rt_sigprocmask(
     Ok(())
 }
 
-#[repr(C)]
-#[derive(Clone, Copy)]
-struct TimeSpec32 {
-    tv_sec: i32,
-    tv_nsec: i32,
-}
-
-#[eonix_macros::define_syscall(SYS_RT_SIGTIMEDWAIT_TIME32)]
-async fn rt_sigtimedwait_time32(
+#[cfg_attr(
+    any(target_arch = "riscv64", target_arch = "loongarch64"),
+    eonix_macros::define_syscall(SYS_RT_SIGTIMEDWAIT)
+)]
+async fn rt_sigtimedwait(
     _uthese: User<SigSet>,
     _uinfo: UserMut<SigInfo>,
-    _uts: User<TimeSpec32>,
+    _uts: User<TimeSpec>,
 ) -> KResult<i32> {
     // TODO
     Ok(0)
@@ -820,7 +779,7 @@ async fn clone(
     clone_flags: usize,
     new_sp: usize,
     parent_tidptr: UserMut<u32>,
-    tls: usize,
+    tls: PtrT,
     child_tidptr: UserMut<u32>,
 ) -> KResult<u32> {
     let clone_args = CloneArgs::for_clone(clone_flags, new_sp, child_tidptr, parent_tidptr, tls)?;
@@ -925,8 +884,23 @@ async fn sigreturn() -> KResult<SyscallNoReturn> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_ARCH_PRCTL)]
-async fn arch_prctl(option: u32, addr: u32) -> KResult<u32> {
-    sys_arch_prctl(thread, option, addr).await
+async fn arch_prctl(option: u32, addr: PtrT) -> KResult<u32> {
+    match option {
+        PR_SET_NAME => {
+            let name = UserPointer::<[u8; 16]>::new(User::with_addr(addr.addr()))?.read()?;
+            let len = name.iter().position(|&c| c == 0).unwrap_or(15);
+            thread.set_name(name[..len].into());
+            Ok(0)
+        }
+        PR_GET_NAME => {
+            let name = thread.get_name();
+            let len = name.len().min(15);
+            let name: [u8; 16] = core::array::from_fn(|i| if i < len { name[i] } else { 0 });
+            UserPointerMut::<[u8; 16]>::new(UserMut::with_addr(addr.addr()))?.write(name)?;
+            Ok(0)
+        }
+        _ => Err(EINVAL),
+    }
 }
 
 pub fn keep_alive() {}

+ 9 - 12
src/kernel/task.rs

@@ -8,6 +8,7 @@ mod process_list;
 mod session;
 mod signal;
 mod thread;
+mod user_tls;
 
 pub use clone::{do_clone, CloneArgs, CloneFlags};
 pub use futex::{futex_wait, futex_wake, parse_futexop, FutexFlags, FutexOp, RobustListHead};
@@ -19,6 +20,7 @@ pub use process_list::ProcessList;
 pub use session::Session;
 pub use signal::SignalAction;
 pub use thread::{yield_now, Thread, ThreadAlloc, ThreadBuilder};
+pub use user_tls::{UserTLS, UserTLSDescriptor};
 
 fn do_block_on<F>(mut future: core::pin::Pin<&mut F>) -> F::Output
 where
@@ -79,30 +81,25 @@ pub async fn stackful<F>(mut future: F) -> F::Output
 where
     F: core::future::Future,
 {
-    use crate::kernel::{
-        interrupt::{default_fault_handler, default_irq_handler},
-        timer::{should_reschedule, timer_interrupt},
-    };
     use alloc::sync::Arc;
     use alloc::task::Wake;
     use core::cell::UnsafeCell;
     use core::future::Future;
     use core::pin::Pin;
     use core::ptr::NonNull;
-    use core::sync::atomic::AtomicBool;
-    use core::sync::atomic::Ordering;
-    use core::task::Context;
-    use core::task::Poll;
-    use core::task::Waker;
-    use eonix_hal::traits::trap::RawTrapContext;
-    use eonix_hal::traits::trap::TrapReturn;
-    use eonix_hal::traits::trap::TrapType;
+    use core::sync::atomic::{AtomicBool, Ordering};
+    use core::task::{Context, Poll, Waker};
+
+    use eonix_hal::traits::trap::{RawTrapContext, TrapReturn, TrapType};
     use eonix_hal::trap::TrapContext;
     use eonix_preempt::assert_preempt_enabled;
     use eonix_runtime::executor::Stack;
     use eonix_runtime::task::Task;
     use thread::wait_for_wakeups;
 
+    use crate::kernel::interrupt::{default_fault_handler, default_irq_handler};
+    use crate::kernel::timer::{should_reschedule, timer_interrupt};
+
     let stack = KernelStack::new();
 
     fn execute<F>(mut future: Pin<&mut F>, output_ptr: NonNull<Option<F::Output>>) -> !

+ 24 - 18
src/kernel/task/clone.rs

@@ -1,18 +1,17 @@
-use crate::{
-    kernel::{
-        syscall::{procops::parse_user_tls, UserMut},
-        task::{alloc_pid, ProcessBuilder, ProcessList, Thread, ThreadBuilder},
-        user::UserPointerMut,
-    },
-    KResult,
-};
-use bitflags::bitflags;
 use core::num::NonZero;
-use eonix_hal::processor::UserTLS;
+
+use bitflags::bitflags;
 use eonix_runtime::scheduler::RUNTIME;
 use eonix_sync::AsProof;
+use posix_types::ctypes::PtrT;
 use posix_types::signal::Signal;
 
+use super::{UserTLS, UserTLSDescriptor};
+use crate::kernel::syscall::UserMut;
+use crate::kernel::task::{alloc_pid, ProcessBuilder, ProcessList, Thread, ThreadBuilder};
+use crate::kernel::user::UserPointerMut;
+use crate::KResult;
+
 bitflags! {
     #[derive(Debug, Default)]
     pub struct CloneFlags: usize {
@@ -46,12 +45,18 @@ bitflags! {
 #[derive(Debug)]
 pub struct CloneArgs {
     pub flags: CloneFlags,
-    pub sp: Option<NonZero<usize>>, // Stack pointer for the new thread.
-    pub exit_signal: Option<Signal>, // Signal to send to the parent on exit.
-    pub set_tid_ptr: Option<UserMut<u32>>, // Pointer to set child TID in user space.
-    pub clear_tid_ptr: Option<UserMut<u32>>, // Pointer to clear child TID in user space.
-    pub parent_tid_ptr: Option<UserMut<u32>>, // Pointer to parent TID in user space.
-    pub tls: Option<UserTLS>,       // Pointer to TLS information.
+    /// Stack pointer for the new thread.
+    pub sp: Option<NonZero<usize>>,
+    /// Signal to send to the parent on exit.
+    pub exit_signal: Option<Signal>,
+    /// Pointer to set child TID in user space.
+    pub set_tid_ptr: Option<UserMut<u32>>,
+    /// Pointer to clear child TID in user space.
+    pub clear_tid_ptr: Option<UserMut<u32>>,
+    /// Pointer to parent TID in user space.
+    pub parent_tid_ptr: Option<UserMut<u32>>,
+    /// Pointer to TLS information.
+    pub tls: Option<UserTLS>,
 }
 
 impl CloneArgs {
@@ -62,7 +67,7 @@ impl CloneArgs {
         sp: usize,
         child_tid_ptr: UserMut<u32>,
         parent_tid_ptr: UserMut<u32>,
-        tls: usize,
+        tls: PtrT,
     ) -> KResult<Self> {
         let clone_flags = CloneFlags::from_bits_truncate(flags & !Self::MASK);
         let exit_signal = flags & Self::MASK;
@@ -87,7 +92,8 @@ impl CloneArgs {
             .then_some(parent_tid_ptr);
 
         let tls = if clone_flags.contains(CloneFlags::CLONE_SETTLS) {
-            Some(parse_user_tls(tls)?)
+            let tls_desc = UserTLSDescriptor::new(tls)?;
+            Some(tls_desc.read()?)
         } else {
             None
         };

+ 30 - 46
src/kernel/task/thread.rs

@@ -1,43 +1,37 @@
-use super::{
-    signal::{RaiseResult, SignalList},
-    stackful, Process, ProcessList, WaitType,
-};
-use crate::{
-    kernel::{
-        interrupt::default_irq_handler,
-        syscall::{syscall_handlers, SyscallHandler, User, UserMut},
-        task::{clone::CloneArgs, futex::RobustListHead, CloneFlags},
-        timer::{should_reschedule, timer_interrupt},
-        user::{UserPointer, UserPointerMut},
-        vfs::{filearray::FileArray, FsContext},
-    },
-    prelude::*,
-};
-use alloc::{alloc::Allocator, sync::Arc};
+use alloc::alloc::Allocator;
+use alloc::sync::Arc;
+use core::future::{poll_fn, Future};
+use core::pin::Pin;
+use core::ptr::NonNull;
+use core::sync::atomic::{AtomicBool, Ordering};
+use core::task::{Context, Poll};
+
 use atomic_unique_refcell::AtomicUniqueRefCell;
-use core::{
-    future::{poll_fn, Future},
-    pin::Pin,
-    ptr::NonNull,
-    sync::atomic::{AtomicBool, Ordering},
-    task::{Context, Poll},
-};
-use eonix_hal::{
-    fpu::FpuState,
-    processor::{UserTLS, CPU},
-    traits::{
-        fault::Fault,
-        fpu::RawFpuState as _,
-        trap::{RawTrapContext, TrapReturn, TrapType},
-    },
-    trap::TrapContext,
-};
+use eonix_hal::fpu::FpuState;
+use eonix_hal::traits::fault::Fault;
+use eonix_hal::traits::fpu::RawFpuState as _;
+use eonix_hal::traits::trap::{RawTrapContext, TrapReturn, TrapType};
+use eonix_hal::trap::TrapContext;
 use eonix_mm::address::{Addr as _, VAddr};
 use eonix_sync::AsProofMut as _;
 use pointers::BorrowedArc;
 use posix_types::signal::Signal;
 use stalloc::UnsafeStalloc;
 
+use super::signal::{RaiseResult, SignalList};
+use super::user_tls::UserTLS;
+use super::{stackful, Process, ProcessList, WaitType};
+use crate::kernel::interrupt::default_irq_handler;
+use crate::kernel::syscall::{syscall_handlers, SyscallHandler, User, UserMut};
+use crate::kernel::task::clone::CloneArgs;
+use crate::kernel::task::futex::RobustListHead;
+use crate::kernel::task::CloneFlags;
+use crate::kernel::timer::{should_reschedule, timer_interrupt};
+use crate::kernel::user::{UserPointer, UserPointerMut};
+use crate::kernel::vfs::filearray::FileArray;
+use crate::kernel::vfs::FsContext;
+use crate::prelude::*;
+
 #[eonix_percpu::define_percpu]
 static CURRENT_THREAD: Option<NonNull<Thread>> = None;
 
@@ -275,12 +269,9 @@ impl Thread {
         self.signal_list.raise(signal)
     }
 
-    /// # Safety
-    /// This function is unsafe because it accesses the `current_cpu()`, which needs
-    /// to be called in a preemption disabled context.
-    pub unsafe fn load_thread_area32(&self) {
+    pub fn activate_tls(&self) {
         if let Some(tls) = self.inner.lock().tls.as_ref() {
-            CPU::local().as_mut().set_tls32(tls);
+            tls.activate();
         }
     }
 
@@ -442,14 +433,7 @@ impl Thread {
 
             CURRENT_THREAD.set(NonNull::new(&raw const *self as *mut _));
 
-            unsafe {
-                eonix_preempt::disable();
-
-                // SAFETY: Preemption is disabled.
-                self.load_thread_area32();
-
-                eonix_preempt::enable();
-            }
+            self.activate_tls();
 
             let result = future.as_mut().poll(cx);
 

+ 34 - 0
src/kernel/task/user_tls/mod.rs

@@ -0,0 +1,34 @@
+cfg_if::cfg_if! {
+    if #[cfg(target_arch = "x86_64")] {
+        mod x86_64;
+        pub use x86_64::*;
+    } else {
+        use eonix_mm::address::VAddr;
+        use posix_types::ctypes::PtrT;
+
+        use crate::prelude::KResult;
+
+
+        #[derive(Debug, Clone)]
+        pub struct UserTLS(VAddr);
+
+        #[derive(Debug, Clone)]
+        pub struct UserTLSDescriptor(VAddr);
+
+        impl UserTLS {
+            pub fn activate(&self) {
+                self.0;
+            }
+        }
+
+        impl UserTLSDescriptor {
+            pub fn new(tp: PtrT) -> KResult<Self> {
+                Ok(Self(VAddr::from(tp.addr())))
+            }
+
+            pub fn read(&self) -> KResult<UserTLS> {
+                Ok(UserTLS(self.0))
+            }
+        }
+    }
+}

+ 83 - 0
src/kernel/task/user_tls/x86_64.rs

@@ -0,0 +1,83 @@
+use core::fmt;
+
+use eonix_hal::arch_exported::gdt::{GDTEntry, GDT};
+use eonix_hal::processor::CPU;
+use eonix_mm::address::VAddr;
+use posix_types::ctypes::PtrT;
+use posix_types::x86_64::UserDescriptor;
+
+use crate::kernel::syscall::{User, UserMut};
+use crate::kernel::user::{CheckedUserPointer, UserPointerMut};
+use crate::prelude::KResult;
+
+#[derive(Debug, Clone)]
+pub struct UserTLS {
+    desc: GDTEntry,
+    base: u64,
+}
+
+pub struct UserTLSDescriptor<'a> {
+    ptr: UserPointerMut<'a, UserDescriptor>,
+}
+
+impl UserTLS {
+    fn new(base: u32, limit: u32) -> Self {
+        Self {
+            desc: GDTEntry::new_tls(base, limit),
+            base: base as u64,
+        }
+    }
+
+    fn new_page_limit(base: u32, limit_in_pages: u32) -> Self {
+        Self {
+            desc: GDTEntry::new_tls_page_limit(base, limit_in_pages),
+            base: base as u64,
+        }
+    }
+
+    pub fn activate(&self) {
+        CPU::local().as_mut().set_tls32(self.desc, self.base);
+    }
+}
+
+impl UserTLSDescriptor<'_> {
+    pub fn new(raw_tls: PtrT) -> KResult<Self> {
+        Ok(Self {
+            ptr: UserPointerMut::new(UserMut::<UserDescriptor>::with_addr(raw_tls.addr()))?,
+        })
+    }
+
+    pub fn read(&self) -> KResult<UserTLS> {
+        let mut desc = self.ptr.read()?;
+
+        let base = VAddr::from(desc.base as usize);
+
+        // Clear the TLS area if it is not present.
+        if desc.flags.is_read_exec_only() && !desc.flags.is_present() {
+            if desc.limit != 0 && base != VAddr::NULL {
+                let len = if desc.flags.is_limit_in_pages() {
+                    (desc.limit as usize) << 12
+                } else {
+                    desc.limit as usize
+                };
+
+                CheckedUserPointer::new(User::new(base), len)?.zero()?;
+            }
+        }
+
+        desc.entry = GDT::TLS32_INDEX as u32;
+        self.ptr.write(desc)?;
+
+        Ok(if desc.flags.is_limit_in_pages() {
+            UserTLS::new_page_limit(desc.base, desc.limit)
+        } else {
+            UserTLS::new(desc.base, desc.limit)
+        })
+    }
+}
+
+impl fmt::Debug for UserTLSDescriptor<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("UserTLSDescriptor").finish_non_exhaustive()
+    }
+}

+ 9 - 12
src/kernel/user/dataflow.rs

@@ -1,18 +1,15 @@
-use crate::{
-    io::{Buffer, FillResult},
-    prelude::*,
-};
-use crate::{
-    io::{IntoStream, Stream},
-    kernel::{
-        constants::{EFAULT, EINVAL},
-        syscall::{User, UserMut},
-    },
-};
-use core::{arch::asm, ffi::CStr, marker::PhantomData};
+use core::arch::asm;
+use core::ffi::CStr;
+use core::marker::PhantomData;
+
 use eonix_mm::address::Addr;
 use eonix_preempt::assert_preempt_enabled;
 
+use crate::io::{Buffer, FillResult, IntoStream, Stream};
+use crate::kernel::constants::{EFAULT, EINVAL};
+use crate::kernel::syscall::{User, UserMut};
+use crate::prelude::*;
+
 pub struct CheckedUserPointer<'a> {
     ptr: User<u8>,
     len: usize,