diff --git a/kernel/driver/net/core/src/socket/tcp.rs b/kernel/driver/net/core/src/socket/tcp.rs index 2b3812db..a8c80903 100644 --- a/kernel/driver/net/core/src/socket/tcp.rs +++ b/kernel/driver/net/core/src/socket/tcp.rs @@ -11,7 +11,7 @@ use async_trait::async_trait; use libk::{ block, error::Error, - task::runtime::{run_with_timeout, FutureTimeout}, + task::runtime::with_timeout, vfs::{ConnectionSocket, FileReadiness, ListenerSocket, Socket}, }; use libk_device::monotonic_timestamp; @@ -64,7 +64,7 @@ impl TcpSocket { ) -> Result<(SocketAddr, Arc), Error> { let future = Self::connect_async(remote); match timeout { - Some(timeout) => run_with_timeout(timeout, future).await.into(), + Some(timeout) => with_timeout(future, timeout).await?.into(), None => future.await, } } @@ -290,10 +290,7 @@ impl TcpSocket { connection.poll_established(cx) }); - match run_with_timeout(timeout, fut).await { - FutureTimeout::Ok(value) => value, - FutureTimeout::Timeout => Err(Error::TimedOut), - } + with_timeout(fut, timeout).await? } } diff --git a/kernel/driver/usb/xhci/src/controller.rs b/kernel/driver/usb/xhci/src/controller.rs index 346d7981..369e63c9 100644 --- a/kernel/driver/usb/xhci/src/controller.rs +++ b/kernel/driver/usb/xhci/src/controller.rs @@ -4,7 +4,7 @@ use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec, vec::Vec}; use atomic_enum::atomic_enum; use device_api::{interrupt::InterruptHandler, Device}; use futures_util::task::AtomicWaker; -use libk::task::runtime::{self, FutureTimeout}; +use libk::task::runtime; use libk_mm::{ address::{AsPhysicalAddress, PhysicalAddress}, PageBox, @@ -278,8 +278,7 @@ impl Xhci { // Wait for port reset // TODO handle disconnect during reset? - let result = runtime::run_with_timeout( - Duration::from_secs(1), + let result = runtime::with_timeout( poll_fn(|cx| { let state = &self.port_states[port]; @@ -290,12 +289,13 @@ impl Xhci { Poll::Pending } }), + Duration::from_secs(1), ) .await; match result { - FutureTimeout::Ok(()) => Ok(()), - FutureTimeout::Timeout => Err(UsbError::PortResetFailed), + Ok(()) => Ok(()), + Err(_) => Err(UsbError::PortResetFailed), } } diff --git a/kernel/libk/libk-mm/interface/src/address.rs b/kernel/libk/libk-mm/interface/src/address.rs index 4f172058..933e4c14 100644 --- a/kernel/libk/libk-mm/interface/src/address.rs +++ b/kernel/libk/libk-mm/interface/src/address.rs @@ -9,8 +9,6 @@ use core::{ use bytemuck::{Pod, Zeroable}; use kernel_arch_interface::mem::KernelTableManager; -use crate::table::EntryLevel; - /// Wrapper type to represent a physical memory address #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Pod, Zeroable)] #[repr(transparent)] diff --git a/kernel/libk/libk-mm/src/process.rs b/kernel/libk/libk-mm/src/process.rs index 9abcf7a1..92969b36 100644 --- a/kernel/libk/libk-mm/src/process.rs +++ b/kernel/libk/libk-mm/src/process.rs @@ -1,4 +1,4 @@ -use core::ops::Range; +use core::ops::{Deref, Range}; use alloc::sync::Arc; use kernel_arch::ProcessAddressSpaceImpl; @@ -7,7 +7,7 @@ use libk_mm_interface::{ process::ProcessAddressSpaceManager, table::{MapAttributes, TableAllocator}, }; -use libk_util::sync::IrqSafeSpinlock; +use libk_util::sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard}; use vmalloc::{RangeData, VirtualMemoryAllocator}; use yggdrasil_abi::error::Error; @@ -26,6 +26,13 @@ pub enum VirtualRangeBacking { File(FileBacking), } +/// Wrapper type for ensuring the translation table cannot be modified while performing accesses +/// to the inner [PhysicalAddress]. +pub struct TranslateGuard<'a, TA: TableAllocator> { + address: PhysicalAddress, + _guard: IrqSafeSpinlockGuard<'a, Inner>, +} + /// Describes a file-backed memory range provider #[derive(Clone)] pub struct FileBacking { @@ -415,6 +422,17 @@ impl ProcessAddressSpace { self.inner.lock().table.translate(address).map(|e| e.0) } + /// Same as [ProcessAddressSpace::translate], except the lock on the address space is held + /// until the resulting [TranslateGuard] is dropped. + pub fn translate_lock(&self, address: usize) -> Result, Error> { + let guard = self.inner.lock(); + let address = guard.table.translate(address).map(|e| e.0)?; + Ok(TranslateGuard { + address, + _guard: guard, + }) + } + /// Removes a single PAGE_SIZE mapping from the address space. /// /// See [ProcessAddressSpaceManager::unmap]. @@ -449,3 +467,11 @@ impl Drop for ProcessAddressSpace { self.clear().ok(); } } + +impl Deref for TranslateGuard<'_, TA> { + type Target = PhysicalAddress; + + fn deref(&self) -> &Self::Target { + &self.address + } +} diff --git a/kernel/libk/src/lib.rs b/kernel/libk/src/lib.rs index 26ebefe6..1fce1d7c 100644 --- a/kernel/libk/src/lib.rs +++ b/kernel/libk/src/lib.rs @@ -20,7 +20,8 @@ trait_upcasting, arbitrary_self_types, slice_split_once, - arbitrary_self_types_pointers + arbitrary_self_types_pointers, + result_flattening )] extern crate alloc; diff --git a/kernel/libk/src/task/binary/elf.rs b/kernel/libk/src/task/binary/elf.rs index 4e57fa13..763ad1a9 100644 --- a/kernel/libk/src/task/binary/elf.rs +++ b/kernel/libk/src/task/binary/elf.rs @@ -5,7 +5,6 @@ use alloc::sync::Arc; use cfg_if::cfg_if; use elf::{ endian::AnyEndian, - io_traits::InputStream, relocation::{Rel, Rela}, segment::ProgramHeader, ElfStream, ParseError, @@ -14,14 +13,14 @@ use libk_mm::{ pointer::PhysicalRefMut, process::{ProcessAddressSpace, VirtualRangeBacking}, table::MapAttributes, - PageBox, L3_PAGE_SIZE, + L3_PAGE_SIZE, }; use libk_util::io::{Read, Seek}; use yggdrasil_abi::{error::Error, io::SeekFrom, path::PathBuf}; use crate::{ random, - task::{mem::ForeignPointer, process::ProcessImage, types::TlsImage}, + task::{process::ProcessImage, types::TlsImage}, }; cfg_if! { diff --git a/kernel/libk/src/task/binary/mod.rs b/kernel/libk/src/task/binary/mod.rs index bb46935c..cb590f76 100644 --- a/kernel/libk/src/task/binary/mod.rs +++ b/kernel/libk/src/task/binary/mod.rs @@ -1,5 +1,3 @@ -use core::{alloc::Layout, ptr::NonNull}; - use alloc::{ borrow::ToOwned, string::String, @@ -18,7 +16,6 @@ use libk_util::io::{Read, Seek}; use yggdrasil_abi::{ error::Error, io::SeekFrom, - pass::{Place, Placer}, path::Path, process::{auxv, AuxValue, ProcessGroupId}, }; diff --git a/kernel/libk/src/task/futex.rs b/kernel/libk/src/task/futex.rs index f8c7769d..3c2538e7 100644 --- a/kernel/libk/src/task/futex.rs +++ b/kernel/libk/src/task/futex.rs @@ -1,27 +1,22 @@ use core::{ future::poll_fn, - pin::Pin, + ptr, sync::atomic::{AtomicU32, Ordering}, - task::{Context, Poll}, + task::Poll, }; use alloc::sync::Arc; -use futures_util::Future; -use libk_mm::{ - address::{AsPhysicalAddress, PhysicalAddress}, - pointer::PhysicalRef, - process::ProcessAddressSpace, -}; +use libk_mm::process::ProcessAddressSpace; use libk_util::waker::QueueWaker; use yggdrasil_abi::error::Error; -use crate::task::thread::Thread; +use crate::task::mem::ForeignAtomic; /// User-space mutex (like BSD/Linux's futex) data structure pub struct UserspaceMutex { queue: QueueWaker, space: Arc, - address: usize, + atomic: *const AtomicU32, } impl UserspaceMutex { @@ -30,35 +25,42 @@ impl UserspaceMutex { Ok(Self { queue: QueueWaker::new(), space: space.clone(), - address, + atomic: ptr::with_exposed_provenance(address), }) } - fn load(&self) -> u32 { - // TODO: this is slow, but this prevents the kernel from reading from unmapped memory - let phys = self.space.translate(self.address).unwrap(); - unsafe { PhysicalRef::::map(phys).load(Ordering::Acquire) } + fn load(&self) -> Result { + self.atomic + .atomic_load_foreign(&self.space, Ordering::Acquire) } - async fn wait_predicate bool>(&self, predicate: P) { + async fn wait_predicate bool>(&self, predicate: P) -> Result<(), Error> { poll_fn(|cx| { - if predicate(self.load()) { - self.queue.remove(cx.waker()); - Poll::Ready(()) - } else { - self.queue.register(cx.waker()); - Poll::Pending + let result = self.load(); + match result { + Err(err) => { + self.queue.remove(cx.waker()); + Poll::Ready(Err(err)) + } + Ok(val) if predicate(val) => { + self.queue.remove(cx.waker()); + Poll::Ready(Ok(())) + } + Ok(_) => { + self.queue.register(cx.waker()); + Poll::Pending + } } }) .await } - pub async fn wait_until(self: Arc, compare_value: u32) { + pub async fn wait_until(self: Arc, compare_value: u32) -> Result<(), Error> { self.wait_predicate(|value| value == compare_value).await } /// Blocks until the value at the mutex's address becomes different from `compare_value` - pub async fn wait(self: Arc, compare_value: u32) { + pub async fn wait(self: Arc, compare_value: u32) -> Result<(), Error> { self.wait_predicate(|value| value != compare_value).await } diff --git a/kernel/libk/src/task/mem.rs b/kernel/libk/src/task/mem.rs index 222cd351..9252d2ba 100644 --- a/kernel/libk/src/task/mem.rs +++ b/kernel/libk/src/task/mem.rs @@ -1,4 +1,9 @@ -use core::{alloc::Layout, mem::size_of}; +use core::{ + alloc::Layout, + mem::size_of, + ptr, + sync::atomic::{AtomicU32, Ordering}, +}; use libk_mm::{address::Virtualize, process::ProcessAddressSpace}; use yggdrasil_abi::error::Error; @@ -96,6 +101,14 @@ pub trait ForeignPointer: Sized { ) -> Result<&'a mut [Self], Error>; } +pub trait ForeignAtomic { + fn atomic_load_foreign( + self: *const Self, + space: &ProcessAddressSpace, + ordering: Ordering, + ) -> Result; +} + impl ForeignPointer for T { unsafe fn write_foreign_volatile(self: *mut Self, space: &ProcessAddressSpace, value: T) { self.try_write_foreign_volatile(space, value) @@ -203,6 +216,23 @@ impl ForeignPointer for T { } } +impl ForeignAtomic for AtomicU32 { + fn atomic_load_foreign( + self: *const Self, + space: &ProcessAddressSpace, + ordering: Ordering, + ) -> Result { + let virt = self.addr(); + if virt % size_of::() != 0 { + // Misaligned atomic + return Err(Error::InvalidMemoryOperation); + } + let phys = space.translate_lock(virt)?; + let phys_virt: *const Self = ptr::with_exposed_provenance(phys.virtualize()); + Ok(unsafe { &*phys_virt }.load(ordering)) + } +} + fn validate_user_align_size(addr: usize, layout: &Layout) -> Result<(), Error> { // Explicitly disallow NULL if addr == 0 { diff --git a/kernel/libk/src/task/process.rs b/kernel/libk/src/task/process.rs index cb725d06..61d486bb 100644 --- a/kernel/libk/src/task/process.rs +++ b/kernel/libk/src/task/process.rs @@ -29,8 +29,7 @@ use yggdrasil_abi::{ use crate::{ task::{ - binary, futex::UserspaceMutex, thread::Thread, types::AllocateProcessId, TaskContextImpl, - ThreadId, + futex::UserspaceMutex, thread::Thread, types::AllocateProcessId, TaskContextImpl, ThreadId, }, vfs::{FileReadiness, FileSet, IoContext, NodeRef}, }; diff --git a/kernel/libk/src/task/runtime/mod.rs b/kernel/libk/src/task/runtime/mod.rs index 25248abf..e3926b37 100644 --- a/kernel/libk/src/task/runtime/mod.rs +++ b/kernel/libk/src/task/runtime/mod.rs @@ -8,4 +8,4 @@ mod timer; pub use executor::{run_to_completion, spawn, spawn_async_worker}; pub use task_queue::init_task_queue; -pub use timer::{run_with_timeout, sleep, tick, FutureTimeout, SleepFuture}; +pub use timer::{maybe_timeout, sleep, tick, with_timeout, SleepFuture}; diff --git a/kernel/libk/src/task/runtime/timer.rs b/kernel/libk/src/task/runtime/timer.rs index 967ba0d1..0c823723 100644 --- a/kernel/libk/src/task/runtime/timer.rs +++ b/kernel/libk/src/task/runtime/timer.rs @@ -1,11 +1,12 @@ use core::{ + future::poll_fn, pin::Pin, task::{Context, Poll, Waker}, time::Duration, }; use alloc::vec::Vec; -use futures_util::{future::BoxFuture, Future, FutureExt}; +use futures_util::{Future, FutureExt}; use libk_util::sync::IrqSafeSpinlock; use yggdrasil_abi::error::Error; @@ -70,11 +71,6 @@ fn register_timeout(duration: Duration, waker: &Waker) { } } -pub enum FutureTimeout { - Ok(T), - Timeout, -} - pub struct SleepFuture { deadline: Duration, } @@ -113,42 +109,33 @@ pub fn sleep(duration: Duration) -> SleepFuture { SleepFuture { deadline } } -pub fn run_with_timeout<'a, T: 'a, F: Future + Send + 'a>( - duration: Duration, +pub fn with_timeout<'a, T: 'a, F: Future + Send + 'a>( fut: F, -) -> impl Future> + 'a { - struct TimeoutFuture<'f, T> { - fut: BoxFuture<'f, T>, - sleep_fut: BoxFuture<'f, ()>, - } + timeout: Duration, +) -> impl Future> + Send + 'a { + let mut fut = fut.boxed(); + let mut sleep_fut = sleep(timeout).boxed(); - impl<'f, T> Future for TimeoutFuture<'f, T> { - type Output = FutureTimeout; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let (timeout, result) = (self.sleep_fut.as_mut().poll(cx), self.fut.as_mut().poll(cx)); - - if let Poll::Ready(result) = result { - Poll::Ready(FutureTimeout::Ok(result)) - } else if timeout.is_ready() { - Poll::Ready(FutureTimeout::Timeout) - } else { - Poll::Pending - } + poll_fn(move |cx| { + let (timeout, output) = (sleep_fut.poll_unpin(cx), fut.poll_unpin(cx)); + if let Poll::Ready(output) = output { + Poll::Ready(Ok(output)) + } else if timeout.is_ready() { + Poll::Ready(Err(Error::TimedOut)) + } else { + Poll::Pending } - } - - TimeoutFuture { - fut: fut.boxed(), - sleep_fut: sleep(duration).boxed(), - } + }) } -impl From>> for Result { - fn from(value: FutureTimeout>) -> Self { - match value { - FutureTimeout::Ok(res) => res, - FutureTimeout::Timeout => Err(Error::TimedOut), +pub fn maybe_timeout<'a, T: 'a, F: Future + Send + 'a>( + fut: F, + timeout: Option, +) -> impl Future> + Send + 'a { + async move { + match timeout { + Some(timeout) => with_timeout(fut, timeout).await, + None => Ok(fut.await), } } } diff --git a/kernel/libk/src/task/thread.rs b/kernel/libk/src/task/thread.rs index 4bc32a7c..240d251c 100644 --- a/kernel/libk/src/task/thread.rs +++ b/kernel/libk/src/task/thread.rs @@ -59,11 +59,6 @@ pub struct ThreadDebuggingInfo { pub breakpoints: BTreeMap, } -struct SignalEntry { - entry: usize, - stack: usize, -} - /// Describes a single thread within the system pub struct Thread { /// Unique thread ID diff --git a/kernel/libk/src/task/types.rs b/kernel/libk/src/task/types.rs index 55eee8bb..f2df3768 100644 --- a/kernel/libk/src/task/types.rs +++ b/kernel/libk/src/task/types.rs @@ -1,11 +1,9 @@ -use alloc::sync::Arc; use core::{ fmt, sync::atomic::{AtomicU32, AtomicU64, Ordering}, }; use atomic_enum::atomic_enum; -use libk_mm::PageBox; use yggdrasil_abi::process::ProcessId; pub trait AllocateProcessId { diff --git a/kernel/libk/src/vfs/socket.rs b/kernel/libk/src/vfs/socket.rs index 89a7f513..afe8d6aa 100644 --- a/kernel/libk/src/vfs/socket.rs +++ b/kernel/libk/src/vfs/socket.rs @@ -1,6 +1,5 @@ use core::{ fmt, - future::Future, task::{Context, Poll}, time::Duration, }; @@ -13,10 +12,7 @@ use yggdrasil_abi::{ net::{SocketAddr, SocketOption}, }; -use crate::{ - task::runtime::{run_with_timeout, FutureTimeout}, - vfs::FileReadiness, -}; +use crate::{task::runtime::maybe_timeout, vfs::FileReadiness}; enum SocketInner { Connection(Arc), @@ -130,7 +126,7 @@ impl SocketWrapper { let (remote, remote_socket) = match (options.non_blocking, options.recv_timeout) { (false, timeout) => { let fut = socket.accept(); - block!(maybe_timeout(timeout, fut).await)?? + block!(maybe_timeout(fut, timeout).await)??? } (true, _) => socket.accept_nonblocking()?, }; @@ -157,11 +153,11 @@ impl SocketWrapper { ) -> Result<(usize, SocketAddr), Error> { match &self.inner { SocketInner::Packet(socket) => { - maybe_timeout(timeout, socket.receive_from(buffer)).await + maybe_timeout(socket.receive_from(buffer), timeout).await? } SocketInner::Connection(socket) => { let remote = socket.remote_address().ok_or(Error::NotConnected)?; - let len = maybe_timeout(timeout, socket.receive(buffer)).await?; + let len = maybe_timeout(socket.receive(buffer), timeout).await??; Ok((len, remote)) } SocketInner::Listener(_) => Err(Error::InvalidOperation), @@ -184,9 +180,9 @@ impl SocketWrapper { ) -> Result { match &self.inner { SocketInner::Packet(socket) => { - maybe_timeout(timeout, socket.send_to(remote, buffer)).await + maybe_timeout(socket.send_to(remote, buffer), timeout).await? } - SocketInner::Connection(socket) => maybe_timeout(timeout, socket.send(buffer)).await, + SocketInner::Connection(socket) => maybe_timeout(socket.send(buffer), timeout).await?, SocketInner::Listener(_) => Err(Error::InvalidOperation), } } @@ -325,20 +321,6 @@ impl Default for InnerOptions { } } -async fn maybe_timeout> + Send>( - timeout: Option, - fut: F, -) -> Result { - if let Some(timeout) = timeout { - match run_with_timeout(timeout, fut).await { - FutureTimeout::Ok(value) => value, - FutureTimeout::Timeout => Err(Error::TimedOut), - } - } else { - fut.await - } -} - // impl From> for SocketWrapper { // fn from(value: Arc) -> Self { // Self::Connection(value) diff --git a/kernel/src/syscall/imp/mod.rs b/kernel/src/syscall/imp/mod.rs index 6c671f47..7a124bb0 100644 --- a/kernel/src/syscall/imp/mod.rs +++ b/kernel/src/syscall/imp/mod.rs @@ -6,7 +6,7 @@ pub(crate) use abi::{ }, mem::{MappingFlags, MappingSource}, net::SocketType, - process::{Signal, SignalEntryData, SpawnOptions, ThreadOption}, + process::{Signal, SignalEntryData, SpawnOptions}, system::SystemInfo, }; use abi::{ diff --git a/kernel/src/syscall/imp/sys_process.rs b/kernel/src/syscall/imp/sys_process.rs index 353d7013..50cd9f2e 100644 --- a/kernel/src/syscall/imp/sys_process.rs +++ b/kernel/src/syscall/imp/sys_process.rs @@ -48,14 +48,12 @@ pub(crate) fn map_memory( } }; - let result = space.allocate( - None, - len, - backing, - MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL, - ); + let mut attrs = MapAttributes::NON_GLOBAL | MapAttributes::USER_READ; + if flags.contains(MappingFlags::WRITE) { + attrs |= MapAttributes::USER_WRITE; + } - result + space.allocate(None, len, backing, attrs) }) } @@ -218,6 +216,8 @@ pub(crate) fn send_signal(pid: ProcessId, signal: Signal) -> Result<(), Error> { Ok(()) } +// TODO this would've been much simpler if physical pages behaved like Rc<...>'s and kernel could +// keep a copy of it, guaranteeing it cannot be freed and remapped into another process. pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error> { let thread = Thread::current(); let process = thread.process(); @@ -225,8 +225,8 @@ pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error> let mutex = process.get_or_insert_mutex((mutex as *const AtomicU32).addr())?; match op { - &MutexOperation::Wait(value, _timeout) => block! { mutex.wait(value).await }, - &MutexOperation::WaitUntil(value, _timeout) => block! { mutex.wait_until(value).await }, + &MutexOperation::Wait(value, _timeout) => block! { mutex.wait(value).await }?, + &MutexOperation::WaitUntil(value, _timeout) => block! { mutex.wait_until(value).await }?, MutexOperation::Wake => { mutex.wake(); Ok(()) @@ -291,7 +291,10 @@ pub(crate) fn wait_thread(id: u32) -> Result<(), Error> { } pub(crate) fn get_thread_option(option: &mut ThreadOption) -> Result<(), Error> { - todo!() + match option { + // There're better ways to do this, don't ask the kernel + ThreadOption::ThreadPointer(_) => Err(Error::InvalidOperation), + } } pub(crate) fn set_thread_option(option: &ThreadOption) -> Result<(), Error> {