Преглед на файлове

syscall: migrate all syscalls to async...

We introduced a per-thread allocator inside the future object to
allocate space for the syscalls. This ensures performance and saves
memory. The allocator takes up 8K for now and is enough for current use.

Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf преди 5 месеца
родител
ревизия
dee96a3a6a

+ 9 - 2
Cargo.lock

@@ -152,6 +152,7 @@ dependencies = [
  "pointers",
  "posix_types",
  "slab_allocator",
+ "stalloc",
  "virtio-drivers",
  "xmas-elf",
 ]
@@ -401,11 +402,17 @@ dependencies = [
  "intrusive_list",
 ]
 
+[[package]]
+name = "stalloc"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a37f0ead4094eeb54c6893316aa139e48b252f1c07511e5124fa1f9414df5b6c"
+
 [[package]]
 name = "syn"
-version = "2.0.103"
+version = "2.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
 dependencies = [
  "proc-macro2",
  "quote",

+ 3 - 0
Cargo.toml

@@ -31,6 +31,9 @@ acpi = "5.2.0"
 align_ext = "0.1.0"
 xmas-elf = "0.10.0"
 ext4_rs = "1.3.2"
+stalloc = { version = "0.6.1", default-features = false, features = [
+    "allocator-api",
+] }
 
 [target.'cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))'.dependencies]
 virtio-drivers = { version = "0.11.0" }

+ 2 - 0
crates/eonix_hal/src/arch/loongarch64/mm.rs

@@ -87,6 +87,8 @@ impl PagingMode for PagingMode48 {
 
 pub type ArchPagingMode = PagingMode48;
 
+unsafe impl Send for RawPageTable48<'_> {}
+
 impl<'a> RawPageTable<'a> for RawPageTable48<'a> {
     type Entry = PTE64;
 

+ 2 - 0
crates/eonix_hal/src/arch/riscv64/mm.rs

@@ -88,6 +88,8 @@ impl PagingMode for PagingModeSv48 {
 
 pub type ArchPagingMode = PagingModeSv48;
 
+unsafe impl Send for RawPageTableSv48<'_> {}
+
 impl<'a> RawPageTable<'a> for RawPageTableSv48<'a> {
     type Entry = PTE64;
 

+ 1 - 1
crates/eonix_mm/src/page_table/page_table.rs

@@ -11,7 +11,7 @@ use crate::{
 };
 use core::{marker::PhantomData, ptr::NonNull};
 
-pub trait RawPageTable<'a>: 'a {
+pub trait RawPageTable<'a>: Send + 'a {
     type Entry: PTE + 'a;
 
     /// Return the entry at the given index.

+ 10 - 0
crates/posix_types/src/result.rs

@@ -13,3 +13,13 @@ impl From<PosixError> for u32 {
         }
     }
 }
+
+impl core::fmt::Debug for PosixError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        match self {
+            Self::EFAULT => write!(f, "EFAULT"),
+            Self::EXDEV => write!(f, "EXDEV"),
+            Self::EINVAL => write!(f, "EINVAL"),
+        }
+    }
+}

+ 40 - 21
macros/src/lib.rs

@@ -18,6 +18,11 @@ fn define_syscall_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
     let args = item.sig.inputs.iter();
     let ty_ret = item.sig.output;
 
+    assert!(
+        item.sig.asyncness.is_some(),
+        "Syscall must be async function"
+    );
+
     let args_mapped = item
         .sig
         .inputs
@@ -100,36 +105,50 @@ fn define_syscall_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
             };
 
         #[link_section = #syscall_fn_section]
-        fn #helper_fn (
-            thd: &crate::kernel::task::Thread,
+        fn #helper_fn <'thd, 'alloc>(
+            thd: &'thd crate::kernel::task::Thread,
+            thd_alloc: crate::kernel::task::ThreadAlloc<'alloc>,
             args: [usize; 6]
-        ) -> Option<usize> {
+        ) -> core::pin::Pin<Box<
+            dyn core::future::Future<Output = Option<usize>> + Send + 'thd,
+            crate::kernel::task::ThreadAlloc<'alloc>
+        >> {
             use crate::kernel::syscall::{FromSyscallArg, SyscallRetVal};
+            use alloc::boxed::Box;
 
             #(#args_mapped)*
 
-            eonix_log::println_trace!(
-                "trace_syscall",
-                "tid{}: {}({}) => {{",
-                thd.tid,
-                #syscall_name_str,
-                format_args!(#trace_format_string, #trace_format_args),
-            );
-
-            let retval = #real_fn(thd, #(#args_call),*).into_retval();
-
-            eonix_log::println_trace!(
-                "trace_syscall",
-                "}} => {:x?}",
-                retval,
-            );
-
-            retval
+            unsafe {
+                core::pin::Pin::new_unchecked(
+                    Box::new_in(
+                        async move {
+                            eonix_log::println_trace!(
+                                "trace_syscall",
+                                "tid{}: {}({}) => {{",
+                                thd.tid,
+                                #syscall_name_str,
+                                format_args!(#trace_format_string, #trace_format_args),
+                            );
+
+                            let retval = #real_fn(thd, #(#args_call),*).await.into_retval();
+
+                            eonix_log::println_trace!(
+                                "trace_syscall",
+                                "}} => {:x?}",
+                                retval,
+                            );
+
+                            retval
+                        },
+                        thd_alloc
+                    )
+                )
+            }
         }
 
         #(#attrs)*
         #[link_section = #syscall_fn_section]
-        #vis fn #real_fn(
+        #vis async fn #real_fn(
             thread: &crate::kernel::task::Thread,
             #(#args),*
         ) #ty_ret #body

+ 3 - 3
src/fs/fat32.rs

@@ -308,11 +308,11 @@ impl Inode for FileInode {
         Ok(buffer.wrote())
     }
 
-    fn write(&self, stream: &mut dyn Stream, offset: WriteOffset) -> KResult<usize> {
+    fn write(&self, _stream: &mut dyn Stream, _offset: WriteOffset) -> KResult<usize> {
         todo!()
     }
 
-    fn write_direct(&self, stream: &mut dyn Stream, offset: WriteOffset) -> KResult<usize> {
+    fn write_direct(&self, _stream: &mut dyn Stream, _offset: WriteOffset) -> KResult<usize> {
         todo!()
     }
 }
@@ -322,7 +322,7 @@ impl PageCacheBackend for FileInode {
         self.read_direct(page, offset)
     }
 
-    fn write_page(&self, page: &CachePage, offset: usize) -> KResult<usize> {
+    fn write_page(&self, _page: &CachePage, _offset: usize) -> KResult<usize> {
         todo!()
     }
 

+ 4 - 2
src/io.rs

@@ -30,7 +30,7 @@ impl FillResult {
     }
 }
 
-pub trait Buffer {
+pub trait Buffer: Send {
     fn total(&self) -> usize;
     fn wrote(&self) -> usize;
 
@@ -49,7 +49,7 @@ pub trait Buffer {
     }
 }
 
-pub trait Stream {
+pub trait Stream: Send {
     fn poll_data<'a>(&mut self, buf: &'a mut [u8]) -> KResult<Option<&'a mut [u8]>>;
     fn ignore(&mut self, len: usize) -> KResult<Option<usize>>;
 }
@@ -131,6 +131,8 @@ pub struct UninitBuffer<'lt, T: Copy + Sized> {
     buffer: ByteBuffer<'lt>,
 }
 
+unsafe impl<'lt, T: Copy> Send for UninitBuffer<'lt, T> {}
+
 impl<'lt, T: Copy + Sized> UninitBuffer<'lt, T> {
     pub fn new() -> Self {
         let mut data = Box::new(MaybeUninit::uninit());

+ 0 - 15
src/kernel/block.rs

@@ -48,21 +48,6 @@ enum BlockDeviceType {
     },
 }
 
-#[derive(Debug, Clone)]
-pub enum FileSystemType {
-    Ext4,
-    Fat32,
-}
-
-impl FileSystemType {
-    pub fn as_str(&self) -> &'static str {
-        match self {
-            FileSystemType::Ext4 => "ext4",
-            FileSystemType::Fat32 => "fat32",
-        }
-    }
-}
-
 pub struct BlockDevice {
     /// Unique device identifier, major and minor numbers
     devid: DevId,

+ 2 - 1
src/kernel/interrupt.rs

@@ -1,4 +1,5 @@
 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::*;
@@ -36,7 +37,7 @@ pub fn default_fault_handler(fault_type: Fault, trap_ctx: &mut TrapContext) {
         } => {
             let fault_pc = VAddr::from(trap_ctx.get_program_counter());
 
-            if let Some(new_pc) = handle_kernel_page_fault(fault_pc, vaddr, error_code) {
+            if let Some(new_pc) = block_on(handle_kernel_page_fault(fault_pc, vaddr, error_code)) {
                 trap_ctx.set_program_counter(new_pc.addr());
             }
         }

+ 5 - 3
src/kernel/mem/mm_area.rs

@@ -2,7 +2,6 @@ use super::mm_list::EMPTY_PAGE;
 use super::paging::AllocZeroed as _;
 use super::{AsMemoryBlock, Mapping, Page, Permission};
 use crate::kernel::constants::EINVAL;
-use crate::kernel::task::block_on;
 use crate::prelude::KResult;
 use core::borrow::Borrow;
 use core::cell::UnsafeCell;
@@ -19,6 +18,9 @@ pub struct MMArea {
     pub is_shared: bool,
 }
 
+unsafe impl Send for MMArea {}
+unsafe impl Sync for MMArea {}
+
 impl Clone for MMArea {
     fn clone(&self) -> Self {
         Self {
@@ -200,7 +202,7 @@ impl MMArea {
         Ok(())
     }
 
-    pub fn handle(&self, pte: &mut impl PTE, offset: usize, write: bool) -> KResult<()> {
+    pub async fn handle(&self, pte: &mut impl PTE, offset: usize, write: bool) -> KResult<()> {
         let mut attr = pte.get_attr().as_page_attr().expect("Not a page attribute");
         let mut pfn = pte.get_pfn();
 
@@ -209,7 +211,7 @@ impl MMArea {
         }
 
         if attr.contains(PageAttribute::MAPPED) {
-            block_on(self.handle_mmap(&mut pfn, &mut attr, offset, write))?;
+            self.handle_mmap(&mut pfn, &mut attr, offset, write).await?;
         }
 
         attr.insert(PageAttribute::ACCESSED);

+ 16 - 14
src/kernel/mem/mm_list.rs

@@ -7,7 +7,6 @@ use super::paging::AllocZeroed as _;
 use super::{AsMemoryBlock, MMArea, Page};
 use crate::kernel::constants::{EEXIST, EFAULT, EINVAL, ENOMEM};
 use crate::kernel::mem::page_alloc::RawPagePtr;
-use crate::kernel::task::block_on;
 use crate::{prelude::*, sync::ArcSwap};
 use alloc::collections::btree_set::BTreeSet;
 use core::fmt;
@@ -488,7 +487,7 @@ impl MMList {
         Ok(())
     }
 
-    pub fn map_vdso(&self) -> KResult<()> {
+    pub async fn map_vdso(&self) -> KResult<()> {
         unsafe extern "C" {
             fn VDSO_PADDR();
         }
@@ -507,7 +506,7 @@ impl MMList {
         const VDSO_SIZE: usize = 0x1000;
 
         let inner = self.inner.borrow();
-        let inner = block_on(inner.lock());
+        let inner = inner.lock().await;
 
         let mut pte_iter = inner
             .page_table
@@ -529,7 +528,7 @@ impl MMList {
         Ok(())
     }
 
-    pub fn mmap_hint(
+    pub async fn mmap_hint(
         &self,
         hint: VAddr,
         len: usize,
@@ -538,7 +537,7 @@ impl MMList {
         is_shared: bool,
     ) -> KResult<VAddr> {
         let inner = self.inner.borrow();
-        let mut inner = block_on(inner.lock());
+        let mut inner = inner.lock().await;
 
         if hint == VAddr::NULL {
             let at = inner.find_available(hint, len).ok_or(ENOMEM)?;
@@ -557,7 +556,7 @@ impl MMList {
         }
     }
 
-    pub fn mmap_fixed(
+    pub async fn mmap_fixed(
         &self,
         at: VAddr,
         len: usize,
@@ -565,14 +564,17 @@ impl MMList {
         permission: Permission,
         is_shared: bool,
     ) -> KResult<VAddr> {
-        block_on(self.inner.borrow().lock())
+        self.inner
+            .borrow()
+            .lock()
+            .await
             .mmap(at, len, mapping.clone(), permission, is_shared)
             .map(|_| at)
     }
 
-    pub fn set_break(&self, pos: Option<VAddr>) -> VAddr {
+    pub async fn set_break(&self, pos: Option<VAddr>) -> VAddr {
         let inner = self.inner.borrow();
-        let mut inner = block_on(inner.lock());
+        let mut inner = inner.lock().await;
 
         // SAFETY: `set_break` is only called in syscalls, where program break should be valid.
         assert!(inner.break_start.is_some() && inner.break_pos.is_some());
@@ -629,9 +631,9 @@ impl MMList {
     }
 
     /// This should be called only **once** for every thread.
-    pub fn register_break(&self, start: VAddr) {
+    pub async fn register_break(&self, start: VAddr) {
         let inner = self.inner.borrow();
-        let mut inner = block_on(inner.lock());
+        let mut inner = inner.lock().await;
         assert!(inner.break_start.is_none() && inner.break_pos.is_none());
 
         inner.break_start = Some(start.into());
@@ -640,7 +642,7 @@ impl MMList {
 
     /// Access the memory area with the given function.
     /// The function will be called with the offset of the area and the slice of the area.
-    pub fn access_mut<F>(&self, start: VAddr, len: usize, func: F) -> KResult<()>
+    pub async fn access_mut<F>(&self, start: VAddr, len: usize, func: F) -> KResult<()>
     where
         F: Fn(usize, &mut [u8]),
     {
@@ -651,7 +653,7 @@ impl MMList {
         }
 
         let inner = self.inner.borrow();
-        let inner = block_on(inner.lock());
+        let inner = inner.lock().await;
 
         let mut offset = 0;
         let mut remaining = len;
@@ -676,7 +678,7 @@ impl MMList {
                 let page_end = page_start + 0x1000;
 
                 // Prepare for the worst case that we might write to the page...
-                area.handle(pte, page_start - area_start, true)?;
+                area.handle(pte, page_start - area_start, true).await?;
 
                 let start_offset;
                 if page_start < current {

+ 12 - 8
src/kernel/mem/mm_list/page_fault.rs

@@ -1,5 +1,5 @@
 use super::{MMList, VAddr};
-use crate::kernel::task::{block_on, Thread};
+use crate::kernel::task::Thread;
 use eonix_hal::mm::flush_tlb;
 use eonix_hal::traits::fault::PageFaultErrorCode;
 use eonix_mm::address::{Addr as _, AddrOps as _, VRange};
@@ -94,6 +94,7 @@ impl MMList {
             addr.floor() - area.range().start(),
             error.contains(PageFaultErrorCode::Write),
         )
+        .await
         .map_err(|_| Signal::SIGBUS)?;
 
         flush_tlb(addr.floor().addr());
@@ -128,7 +129,7 @@ fn kernel_page_fault_die(vaddr: VAddr, pc: VAddr) -> ! {
     )
 }
 
-pub fn handle_kernel_page_fault(
+pub async fn handle_kernel_page_fault(
     fault_pc: VAddr,
     addr: VAddr,
     error: PageFaultErrorCode,
@@ -148,7 +149,7 @@ pub fn handle_kernel_page_fault(
 
     let mms = &Thread::current().process.mm_list;
     let inner = mms.inner.borrow();
-    let inner = block_on(inner.lock());
+    let inner = inner.lock().await;
 
     let area = match inner.areas.get(&VRange::from(addr)) {
         Some(area) => area,
@@ -163,11 +164,14 @@ pub fn handle_kernel_page_fault(
         .next()
         .expect("If we can find the mapped area, we should be able to find the PTE");
 
-    if let Err(_) = area.handle(
-        pte,
-        addr.floor() - area.range().start(),
-        error.contains(PageFaultErrorCode::Write),
-    ) {
+    if let Err(_) = area
+        .handle(
+            pte,
+            addr.floor() - area.range().start(),
+            error.contains(PageFaultErrorCode::Write),
+        )
+        .await
+    {
         return Some(try_page_fault_fix(fault_pc, addr));
     }
 

+ 2 - 0
src/kernel/mem/page_cache.rs

@@ -26,6 +26,8 @@ unsafe impl Sync for PageCache {}
 #[derive(Clone, Copy)]
 pub struct CachePage(RawPagePtr);
 
+unsafe impl Send for CachePage {}
+
 impl Buffer for CachePage {
     fn total(&self) -> usize {
         PAGE_SIZE

+ 157 - 8
src/kernel/syscall.rs

@@ -1,5 +1,10 @@
+use super::task::ThreadAlloc;
 use crate::kernel::task::Thread;
+use alloc::boxed::Box;
+use core::{future::Future, marker::PhantomData, ops::Deref, pin::Pin};
+use eonix_mm::address::{Addr, VAddr};
 use eonix_sync::LazyLock;
+use posix_types::ctypes::PtrT;
 
 pub mod file_rw;
 pub mod mm;
@@ -12,15 +17,33 @@ const MAX_SYSCALL_NO: usize = 512;
 #[derive(Debug, Clone, Copy)]
 pub struct SyscallNoReturn;
 
+#[derive(Clone, Copy)]
+pub struct User<T>(VAddr, PhantomData<T>);
+
+#[derive(Clone, Copy)]
+pub struct UserMut<T>(VAddr, PhantomData<T>);
+
 #[repr(C)]
 pub(self) struct RawSyscallHandler {
     no: usize,
-    handler: fn(&Thread, [usize; 6]) -> Option<usize>,
+    handler: for<'thd, 'alloc> fn(
+        &'thd Thread,
+        ThreadAlloc<'alloc>,
+        [usize; 6],
+    ) -> Pin<
+        Box<dyn Future<Output = Option<usize>> + Send + 'thd, ThreadAlloc<'alloc>>,
+    >,
     name: &'static str,
 }
 
 pub struct SyscallHandler {
-    pub handler: fn(&Thread, [usize; 6]) -> Option<usize>,
+    pub handler: for<'thd, 'alloc> fn(
+        &'thd Thread,
+        ThreadAlloc<'alloc>,
+        [usize; 6],
+    ) -> Pin<
+        Box<dyn Future<Output = Option<usize>> + Send + 'thd, ThreadAlloc<'alloc>>,
+    >,
     pub name: &'static str,
 }
 
@@ -80,6 +103,18 @@ impl SyscallRetVal for SyscallNoReturn {
     }
 }
 
+impl<T> SyscallRetVal for User<T> {
+    fn into_retval(self) -> Option<usize> {
+        Some(self.0.addr())
+    }
+}
+
+impl<T> SyscallRetVal for UserMut<T> {
+    fn into_retval(self) -> Option<usize> {
+        Some(self.0.addr())
+    }
+}
+
 #[cfg(not(target_arch = "x86_64"))]
 impl SyscallRetVal for u64 {
     fn into_retval(self) -> Option<usize> {
@@ -112,15 +147,129 @@ impl FromSyscallArg for usize {
     }
 }
 
-impl<T> FromSyscallArg for *const T {
-    fn from_arg(value: usize) -> *const T {
-        value as *const T
+impl FromSyscallArg for PtrT {
+    fn from_arg(value: usize) -> Self {
+        PtrT::new(value).expect("Invalid user pointer value")
+    }
+}
+
+impl<T> FromSyscallArg for User<T> {
+    fn from_arg(value: usize) -> User<T> {
+        User(VAddr::from(value), PhantomData)
+    }
+}
+
+impl<T> FromSyscallArg for UserMut<T> {
+    fn from_arg(value: usize) -> UserMut<T> {
+        UserMut(VAddr::from(value), PhantomData)
+    }
+}
+
+impl<T> User<T> {
+    pub const fn new(addr: VAddr) -> Self {
+        Self(addr, PhantomData)
+    }
+
+    pub const fn with_addr(addr: usize) -> Self {
+        Self::new(VAddr::from(addr))
+    }
+
+    pub const fn null() -> Self {
+        Self(VAddr::NULL, PhantomData)
+    }
+
+    pub fn is_null(&self) -> bool {
+        self.0.addr() == 0
+    }
+
+    pub const fn cast<U>(self) -> User<U> {
+        User(self.0, PhantomData)
+    }
+
+    pub fn offset(self, off: isize) -> Self {
+        Self(
+            VAddr::from(
+                self.0
+                    .addr()
+                    .checked_add_signed(off)
+                    .expect("offset overflow"),
+            ),
+            PhantomData,
+        )
+    }
+
+    pub const unsafe fn as_mut(self) -> UserMut<T> {
+        UserMut(self.0, PhantomData)
+    }
+}
+
+impl<T> UserMut<T> {
+    pub const fn new(addr: VAddr) -> Self {
+        Self(addr, PhantomData)
+    }
+
+    pub const fn with_addr(addr: usize) -> Self {
+        Self::new(VAddr::from(addr))
+    }
+
+    pub const fn null() -> Self {
+        Self(VAddr::NULL, PhantomData)
+    }
+
+    pub fn is_null(&self) -> bool {
+        self.0.addr() == 0
+    }
+
+    pub const fn cast<U>(self) -> UserMut<U> {
+        UserMut(self.0, PhantomData)
+    }
+
+    pub fn offset(self, off: isize) -> Self {
+        Self(
+            VAddr::from(
+                self.0
+                    .addr()
+                    .checked_add_signed(off)
+                    .expect("offset overflow"),
+            ),
+            PhantomData,
+        )
+    }
+
+    pub const fn as_const(self) -> User<T> {
+        User(self.0, PhantomData)
+    }
+
+    pub const fn vaddr(&self) -> VAddr {
+        self.0
+    }
+}
+
+impl<T> Deref for User<T> {
+    type Target = VAddr;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> Deref for UserMut<T> {
+    type Target = VAddr;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> core::fmt::Debug for User<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "User({:#x?})", self.0.addr())
     }
 }
 
-impl<T> FromSyscallArg for *mut T {
-    fn from_arg(value: usize) -> *mut T {
-        value as *mut T
+impl<T> core::fmt::Debug for UserMut<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "UserMut({:#x?})", self.0.addr())
     }
 }
 

+ 146 - 113
src/kernel/syscall/file_rw.rs

@@ -1,18 +1,16 @@
-use super::FromSyscallArg;
+use super::{FromSyscallArg, User};
 use crate::io::IntoStream;
 use crate::kernel::constants::{
     EBADF, EFAULT, EINVAL, ENOENT, ENOSYS, ENOTDIR, SEEK_CUR, SEEK_END, SEEK_SET, S_IFBLK, S_IFCHR,
 };
-use crate::kernel::task::{block_on, Thread};
+use crate::kernel::syscall::UserMut;
+use crate::kernel::task::Thread;
 use crate::kernel::timer::sleep;
 use crate::kernel::vfs::filearray::FD;
 use crate::{
     io::{Buffer, BufferFill},
     kernel::{
-        user::{
-            dataflow::{CheckedUserPointer, UserBuffer, UserString},
-            UserPointer, UserPointerMut,
-        },
+        user::{CheckedUserPointer, UserBuffer, UserPointer, UserPointerMut, UserString},
         vfs::{
             dentry::Dentry,
             file::{PollEvent, SeekOption},
@@ -47,7 +45,7 @@ impl FromSyscallArg for AtFlags {
 fn dentry_from(
     thread: &Thread,
     dirfd: FD,
-    pathname: *const u8,
+    pathname: User<u8>,
     follow_symlink: bool,
 ) -> KResult<Arc<Dentry>> {
     let path = UserString::new(pathname)?;
@@ -72,83 +70,91 @@ fn dentry_from(
 }
 
 #[eonix_macros::define_syscall(SYS_READ)]
-fn read(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
+async fn read(fd: FD, buffer: UserMut<u8>, bufsize: usize) -> KResult<usize> {
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
-    block_on(thread.files.get(fd).ok_or(EBADF)?.read(&mut buffer, None))
+    thread
+        .files
+        .get(fd)
+        .ok_or(EBADF)?
+        .read(&mut buffer, None)
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_PREAD64)]
-fn pread64(fd: FD, buffer: *mut u8, bufsize: usize, offset: usize) -> KResult<usize> {
+async fn pread64(fd: FD, buffer: UserMut<u8>, bufsize: usize, offset: usize) -> KResult<usize> {
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
-    block_on(
-        thread
-            .files
-            .get(fd)
-            .ok_or(EBADF)?
-            .read(&mut buffer, Some(offset)),
-    )
+    thread
+        .files
+        .get(fd)
+        .ok_or(EBADF)?
+        .read(&mut buffer, Some(offset))
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_WRITE)]
-fn write(fd: FD, buffer: *const u8, count: usize) -> KResult<usize> {
+async fn write(fd: FD, buffer: User<u8>, count: usize) -> KResult<usize> {
     let buffer = CheckedUserPointer::new(buffer, count)?;
     let mut stream = buffer.into_stream();
 
-    block_on(thread.files.get(fd).ok_or(EBADF)?.write(&mut stream, None))
+    thread
+        .files
+        .get(fd)
+        .ok_or(EBADF)?
+        .write(&mut stream, None)
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_PWRITE64)]
-fn pwrite64(fd: FD, buffer: *const u8, count: usize, offset: usize) -> KResult<usize> {
+async fn pwrite64(fd: FD, buffer: User<u8>, count: usize, offset: usize) -> KResult<usize> {
     let buffer = CheckedUserPointer::new(buffer, count)?;
     let mut stream = buffer.into_stream();
 
-    block_on(
-        thread
-            .files
-            .get(fd)
-            .ok_or(EBADF)?
-            .write(&mut stream, Some(offset)),
-    )
+    thread
+        .files
+        .get(fd)
+        .ok_or(EBADF)?
+        .write(&mut stream, Some(offset))
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_OPENAT)]
-fn openat(dirfd: FD, pathname: *const u8, flags: OpenFlags, mode: u32) -> KResult<FD> {
+async fn openat(dirfd: FD, pathname: User<u8>, flags: OpenFlags, mode: u32) -> KResult<FD> {
     let dentry = dentry_from(thread, dirfd, pathname, flags.follow_symlink())?;
     thread.files.open(&dentry, flags, mode)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_OPEN)]
-fn open(path: *const u8, flags: OpenFlags, mode: u32) -> KResult<FD> {
-    sys_openat(thread, FD::AT_FDCWD, path, flags, mode)
+async fn open(path: User<u8>, flags: OpenFlags, mode: u32) -> KResult<FD> {
+    sys_openat(thread, FD::AT_FDCWD, path, flags, mode).await
 }
 
 #[eonix_macros::define_syscall(SYS_CLOSE)]
-fn close(fd: FD) -> KResult<()> {
+async fn close(fd: FD) -> KResult<()> {
     thread.files.close(fd)
 }
 
 #[eonix_macros::define_syscall(SYS_DUP)]
-fn dup(fd: FD) -> KResult<FD> {
+async fn dup(fd: FD) -> KResult<FD> {
     thread.files.dup(fd)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_DUP2)]
-fn dup2(old_fd: FD, new_fd: FD) -> KResult<FD> {
+async fn dup2(old_fd: FD, new_fd: FD) -> KResult<FD> {
     thread.files.dup_to(old_fd, new_fd, OpenFlags::empty())
 }
 
 #[eonix_macros::define_syscall(SYS_DUP3)]
-fn dup3(old_fd: FD, new_fd: FD, flags: OpenFlags) -> KResult<FD> {
+async fn dup3(old_fd: FD, new_fd: FD, flags: OpenFlags) -> KResult<FD> {
     thread.files.dup_to(old_fd, new_fd, flags)
 }
 
 #[eonix_macros::define_syscall(SYS_PIPE2)]
-fn pipe2(pipe_fd: *mut [FD; 2], flags: OpenFlags) -> KResult<()> {
-    let mut buffer = UserBuffer::new(pipe_fd as *mut u8, core::mem::size_of::<[FD; 2]>())?;
+async fn pipe2(pipe_fd: UserMut<[FD; 2]>, flags: OpenFlags) -> KResult<()> {
+    let mut buffer = UserBuffer::new(pipe_fd.cast(), core::mem::size_of::<[FD; 2]>())?;
     let (read_fd, write_fd) = thread.files.pipe(flags)?;
 
     buffer.copy(&[read_fd, write_fd])?.ok_or(EFAULT)
@@ -156,13 +162,13 @@ fn pipe2(pipe_fd: *mut [FD; 2], flags: OpenFlags) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_PIPE)]
-fn pipe(pipe_fd: *mut [FD; 2]) -> KResult<()> {
-    sys_pipe2(thread, pipe_fd, OpenFlags::empty())
+async fn pipe(pipe_fd: UserMut<[FD; 2]>) -> KResult<()> {
+    sys_pipe2(thread, pipe_fd, OpenFlags::empty()).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_GETDENTS)]
-fn getdents(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
+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)?;
@@ -170,7 +176,7 @@ fn getdents(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETDENTS64)]
-fn getdents64(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
+async fn getdents64(fd: FD, buffer: UserMut<u8>, bufsize: usize) -> KResult<usize> {
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
     thread.files.get(fd).ok_or(EBADF)?.getdents64(&mut buffer)?;
@@ -182,7 +188,12 @@ fn getdents64(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
     eonix_macros::define_syscall(SYS_NEWFSTATAT)
 )]
 #[cfg_attr(target_arch = "x86_64", eonix_macros::define_syscall(SYS_FSTATAT64))]
-fn newfstatat(dirfd: FD, pathname: *const u8, statbuf: *mut Stat, flags: AtFlags) -> KResult<()> {
+async fn newfstatat(
+    dirfd: FD,
+    pathname: User<u8>,
+    statbuf: UserMut<Stat>,
+    flags: AtFlags,
+) -> KResult<()> {
     let dentry = if flags.at_empty_path() {
         let file = thread.files.get(dirfd).ok_or(EBADF)?;
         file.as_path().ok_or(EBADF)?.clone()
@@ -205,23 +216,17 @@ fn newfstatat(dirfd: FD, pathname: *const u8, statbuf: *mut Stat, flags: AtFlags
     eonix_macros::define_syscall(SYS_NEWFSTAT)
 )]
 #[cfg_attr(target_arch = "x86_64", eonix_macros::define_syscall(SYS_FSTAT64))]
-fn newfstat(fd: FD, statbuf: *mut Stat) -> KResult<()> {
-    sys_newfstatat(
-        thread,
-        fd,
-        core::ptr::null(),
-        statbuf,
-        AtFlags::AT_EMPTY_PATH,
-    )
+async fn newfstat(fd: FD, statbuf: UserMut<Stat>) -> KResult<()> {
+    sys_newfstatat(thread, fd, User::null(), statbuf, AtFlags::AT_EMPTY_PATH).await
 }
 
 #[eonix_macros::define_syscall(SYS_STATX)]
-fn statx(
+async fn statx(
     dirfd: FD,
-    pathname: *const u8,
+    pathname: User<u8>,
     flags: AtFlags,
     mask: u32,
-    buffer: *mut StatX,
+    buffer: UserMut<StatX>,
 ) -> KResult<()> {
     if !flags.statx_default_sync() {
         unimplemented!("statx with no default sync flags: {:?}", flags);
@@ -244,7 +249,7 @@ fn statx(
 }
 
 #[eonix_macros::define_syscall(SYS_MKDIRAT)]
-fn mkdirat(dirfd: FD, pathname: *const u8, mode: u32) -> KResult<()> {
+async fn mkdirat(dirfd: FD, pathname: User<u8>, mode: u32) -> KResult<()> {
     let umask = *thread.fs_context.umask.lock();
     let mode = mode & !umask & 0o777;
 
@@ -254,19 +259,19 @@ fn mkdirat(dirfd: FD, pathname: *const u8, mode: u32) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_MKDIR)]
-fn mkdir(pathname: *const u8, mode: u32) -> KResult<()> {
-    sys_mkdirat(thread, FD::AT_FDCWD, pathname, mode)
+async fn mkdir(pathname: User<u8>, mode: u32) -> KResult<()> {
+    sys_mkdirat(thread, FD::AT_FDCWD, pathname, mode).await
 }
 
 #[eonix_macros::define_syscall(SYS_FTRUNCATE64)]
-fn truncate64(fd: FD, length: usize) -> KResult<()> {
+async fn truncate64(fd: FD, length: usize) -> KResult<()> {
     let file = thread.files.get(fd).ok_or(EBADF)?;
     file.as_path().ok_or(EBADF)?.truncate(length)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_TRUNCATE)]
-fn truncate(pathname: *const u8, length: usize) -> KResult<()> {
+async fn truncate(pathname: User<u8>, length: usize) -> KResult<()> {
     let path = UserString::new(pathname)?;
     let path = Path::new(path.as_cstr().to_bytes())?;
 
@@ -276,18 +281,18 @@ fn truncate(pathname: *const u8, length: usize) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_UNLINKAT)]
-fn unlinkat(dirfd: FD, pathname: *const u8) -> KResult<()> {
+async fn unlinkat(dirfd: FD, pathname: User<u8>) -> KResult<()> {
     dentry_from(thread, dirfd, pathname, false)?.unlink()
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_UNLINK)]
-fn unlink(pathname: *const u8) -> KResult<()> {
+async fn unlink(pathname: User<u8>) -> KResult<()> {
     sys_unlinkat(thread, FD::AT_FDCWD, pathname)
 }
 
 #[eonix_macros::define_syscall(SYS_SYMLINKAT)]
-fn symlinkat(target: *const u8, dirfd: FD, linkpath: *const u8) -> KResult<()> {
+async fn symlinkat(target: User<u8>, dirfd: FD, linkpath: User<u8>) -> KResult<()> {
     let target = UserString::new(target)?;
     let dentry = dentry_from(thread, dirfd, linkpath, false)?;
 
@@ -296,12 +301,12 @@ fn symlinkat(target: *const u8, dirfd: FD, linkpath: *const u8) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SYMLINK)]
-fn symlink(target: *const u8, linkpath: *const u8) -> KResult<()> {
+async fn symlink(target: User<u8>, linkpath: User<u8>) -> KResult<()> {
     sys_symlinkat(thread, target, FD::AT_FDCWD, linkpath)
 }
 
 #[eonix_macros::define_syscall(SYS_MKNODAT)]
-fn mknodat(dirfd: FD, pathname: *const u8, mode: u32, dev: u32) -> KResult<()> {
+async fn mknodat(dirfd: FD, pathname: User<u8>, mode: u32, dev: u32) -> KResult<()> {
     let dentry = dentry_from(thread, dirfd, pathname, true)?;
 
     let umask = *thread.fs_context.umask.lock();
@@ -312,12 +317,17 @@ fn mknodat(dirfd: FD, pathname: *const u8, mode: u32, dev: u32) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_MKNOD)]
-fn mknod(pathname: *const u8, mode: u32, dev: u32) -> KResult<()> {
-    sys_mknodat(thread, FD::AT_FDCWD, pathname, mode, dev)
+async fn mknod(pathname: User<u8>, mode: u32, dev: u32) -> KResult<()> {
+    sys_mknodat(thread, FD::AT_FDCWD, pathname, mode, dev).await
 }
 
 #[eonix_macros::define_syscall(SYS_READLINKAT)]
-fn readlinkat(dirfd: FD, pathname: *const u8, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
+async fn readlinkat(
+    dirfd: FD,
+    pathname: User<u8>,
+    buffer: UserMut<u8>,
+    bufsize: usize,
+) -> KResult<usize> {
     let dentry = dentry_from(thread, dirfd, pathname, false)?;
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
@@ -326,11 +336,11 @@ fn readlinkat(dirfd: FD, pathname: *const u8, buffer: *mut u8, bufsize: usize) -
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_READLINK)]
-fn readlink(pathname: *const u8, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
-    sys_readlinkat(thread, FD::AT_FDCWD, pathname, buffer, bufsize)
+async fn readlink(pathname: User<u8>, buffer: UserMut<u8>, bufsize: usize) -> KResult<usize> {
+    sys_readlinkat(thread, FD::AT_FDCWD, pathname, buffer, bufsize).await
 }
 
-fn do_lseek(thread: &Thread, fd: FD, offset: u64, whence: u32) -> KResult<u64> {
+async fn do_lseek(thread: &Thread, fd: FD, offset: u64, whence: u32) -> KResult<u64> {
     let file = thread.files.get(fd).ok_or(EBADF)?;
 
     Ok(match whence {
@@ -343,17 +353,23 @@ fn do_lseek(thread: &Thread, fd: FD, offset: u64, whence: u32) -> KResult<u64> {
 
 #[cfg(not(target_arch = "x86_64"))]
 #[eonix_macros::define_syscall(SYS_LSEEK)]
-fn lseek(fd: FD, offset: u64, whence: u32) -> KResult<u64> {
-    do_lseek(thread, fd, offset, whence)
+async fn lseek(fd: FD, offset: u64, whence: u32) -> KResult<u64> {
+    do_lseek(thread, fd, offset, whence).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_LLSEEK)]
-fn llseek(fd: FD, offset_high: u32, offset_low: u32, result: *mut u64, whence: u32) -> KResult<()> {
-    let mut result = UserBuffer::new(result as *mut u8, core::mem::size_of::<u64>())?;
+fn llseek(
+    fd: FD,
+    offset_high: u32,
+    offset_low: u32,
+    result: UserMut<u64>,
+    whence: u32,
+) -> KResult<()> {
+    let mut result = UserBuffer::new(result.cast(), core::mem::size_of::<u64>())?;
     let offset = ((offset_high as u64) << 32) | (offset_low as u64);
 
-    let new_offset = do_lseek(thread, fd, offset, whence)?;
+    let new_offset = do_lseek(thread, fd, offset, whence).await?;
 
     result.copy(&new_offset)?.ok_or(EFAULT)
 }
@@ -366,7 +382,7 @@ struct IoVec {
 }
 
 #[eonix_macros::define_syscall(SYS_READV)]
-fn readv(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
+async fn readv(fd: FD, iov_user: User<IoVec>, iovcnt: u32) -> KResult<usize> {
     let file = thread.files.get(fd).ok_or(EBADF)?;
 
     let mut iov_user = UserPointer::new(iov_user)?;
@@ -381,14 +397,16 @@ fn readv(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
             Ok(IoVec {
                 len: Long::ZERO, ..
             }) => None,
-            Ok(IoVec { base, len }) => Some(UserBuffer::new(base.addr() as *mut u8, len.get())),
+            Ok(IoVec { base, len }) => {
+                Some(UserBuffer::new(UserMut::with_addr(base.addr()), len.get()))
+            }
         })
         .collect::<KResult<Vec<_>>>()?;
 
     let mut tot = 0usize;
     for mut buffer in iov_buffers.into_iter() {
         // TODO!!!: `readv`
-        let nread = block_on(file.read(&mut buffer, None))?;
+        let nread = file.read(&mut buffer, None).await?;
         tot += nread;
 
         if nread != buffer.total() {
@@ -400,7 +418,7 @@ fn readv(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_WRITEV)]
-fn writev(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
+async fn writev(fd: FD, iov_user: User<IoVec>, iovcnt: u32) -> KResult<usize> {
     let file = thread.files.get(fd).ok_or(EBADF)?;
 
     let mut iov_user = UserPointer::new(iov_user)?;
@@ -416,7 +434,7 @@ fn writev(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
                 len: Long::ZERO, ..
             }) => None,
             Ok(IoVec { base, len }) => Some(
-                CheckedUserPointer::new(base.addr() as *mut u8, len.get())
+                CheckedUserPointer::new(User::with_addr(base.addr()), len.get())
                     .map(|ptr| ptr.into_stream()),
             ),
         })
@@ -424,7 +442,7 @@ fn writev(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
 
     let mut tot = 0usize;
     for mut stream in iov_streams.into_iter() {
-        let nread = block_on(file.write(&mut stream, None))?;
+        let nread = file.write(&mut stream, None).await?;
         tot += nread;
 
         if nread == 0 || !stream.is_drained() {
@@ -436,7 +454,7 @@ fn writev(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_FACCESSAT)]
-fn faccessat(dirfd: FD, pathname: *const u8, _mode: u32, flags: AtFlags) -> KResult<()> {
+async fn faccessat(dirfd: FD, pathname: User<u8>, _mode: u32, flags: AtFlags) -> KResult<()> {
     let dentry = if flags.at_empty_path() {
         let file = thread.files.get(dirfd).ok_or(EBADF)?;
         file.as_path().ok_or(EBADF)?.clone()
@@ -462,12 +480,12 @@ fn faccessat(dirfd: FD, pathname: *const u8, _mode: u32, flags: AtFlags) -> KRes
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_ACCESS)]
-fn access(pathname: *const u8, mode: u32) -> KResult<()> {
-    sys_faccessat(thread, FD::AT_FDCWD, pathname, mode, AtFlags::empty())
+async fn access(pathname: User<u8>, mode: u32) -> KResult<()> {
+    sys_faccessat(thread, FD::AT_FDCWD, pathname, mode, AtFlags::empty()).await
 }
 
 #[eonix_macros::define_syscall(SYS_SENDFILE64)]
-fn sendfile64(out_fd: FD, in_fd: FD, offset: *mut u8, count: usize) -> KResult<usize> {
+async fn sendfile64(out_fd: FD, in_fd: FD, offset: UserMut<u8>, count: usize) -> KResult<usize> {
     let in_file = thread.files.get(in_fd).ok_or(EBADF)?;
     let out_file = thread.files.get(out_fd).ok_or(EBADF)?;
 
@@ -475,18 +493,18 @@ fn sendfile64(out_fd: FD, in_fd: FD, offset: *mut u8, count: usize) -> KResult<u
         unimplemented!("sendfile64 with offset");
     }
 
-    block_on(in_file.sendfile(&out_file, count))
+    in_file.sendfile(&out_file, count).await
 }
 
 #[eonix_macros::define_syscall(SYS_IOCTL)]
-fn ioctl(fd: FD, request: usize, arg3: usize) -> KResult<usize> {
+async fn ioctl(fd: FD, request: usize, arg3: usize) -> KResult<usize> {
     let file = thread.files.get(fd).ok_or(EBADF)?;
 
     file.ioctl(request, arg3)
 }
 
 #[eonix_macros::define_syscall(SYS_FCNTL64)]
-fn fcntl64(fd: FD, cmd: u32, arg: usize) -> KResult<usize> {
+async fn fcntl64(fd: FD, cmd: u32, arg: usize) -> KResult<usize> {
     thread.files.fcntl(fd, cmd, arg)
 }
 
@@ -498,7 +516,12 @@ struct UserPollFd {
     revents: u16,
 }
 
-fn do_poll(thread: &Thread, fds: *mut UserPollFd, nfds: u32, _timeout: u32) -> KResult<u32> {
+async fn do_poll(
+    thread: &Thread,
+    fds: UserMut<UserPollFd>,
+    nfds: u32,
+    _timeout: u32,
+) -> KResult<u32> {
     match nfds {
         0 => Ok(0),
         2.. => unimplemented!("Poll with {} fds", nfds),
@@ -511,7 +534,10 @@ fn do_poll(thread: &Thread, fds: *mut UserPollFd, nfds: u32, _timeout: u32) -> K
             let mut fd = fds.read()?;
 
             let file = thread.files.get(fd.fd).ok_or(EBADF)?;
-            fd.revents = block_on(file.poll(PollEvent::from_bits_retain(fd.events)))?.bits();
+            fd.revents = file
+                .poll(PollEvent::from_bits_retain(fd.events))
+                .await?
+                .bits();
 
             fds.write(fd)?;
             Ok(1)
@@ -520,24 +546,24 @@ fn do_poll(thread: &Thread, fds: *mut UserPollFd, nfds: u32, _timeout: u32) -> K
 }
 
 #[eonix_macros::define_syscall(SYS_PPOLL)]
-fn ppoll(
-    fds: *mut UserPollFd,
+async fn ppoll(
+    fds: UserMut<UserPollFd>,
     nfds: u32,
-    _timeout_ptr: *const TimeSpec,
-    _sigmask: *const SigSet,
+    _timeout_ptr: User<TimeSpec>,
+    _sigmask: User<SigSet>,
 ) -> KResult<u32> {
     // TODO: Implement ppoll with signal mask and timeout
-    do_poll(thread, fds, nfds, 0)
+    do_poll(thread, fds, nfds, 0).await
 }
 
 #[eonix_macros::define_syscall(SYS_PSELECT6)]
-fn pselect6(
+async fn pselect6(
     nfds: u32,
-    _readfds: *mut FDSet,
-    _writefds: *mut FDSet,
-    _exceptfds: *mut FDSet,
-    timeout: *mut TimeSpec,
-    _sigmask: *const (),
+    _readfds: UserMut<FDSet>,
+    _writefds: UserMut<FDSet>,
+    _exceptfds: UserMut<FDSet>,
+    timeout: UserMut<TimeSpec>,
+    _sigmask: User<()>,
 ) -> KResult<usize> {
     // According to [pthread6(2)](https://linux.die.net/man/2/pselect6):
     // Some code calls select() with all three sets empty, nfds zero, and
@@ -552,7 +578,7 @@ fn pselect6(
     // Read here to check for invalid pointers.
     let _timeout_value = timeout.read()?;
 
-    block_on(sleep(Duration::from_millis(10)));
+    sleep(Duration::from_millis(10)).await;
 
     timeout.write(TimeSpec {
         tv_sec: 0,
@@ -564,12 +590,18 @@ fn pselect6(
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_POLL)]
-fn poll(fds: *mut UserPollFd, nfds: u32, timeout: u32) -> KResult<u32> {
-    do_poll(thread, fds, nfds, timeout)
+async fn poll(fds: UserMut<UserPollFd>, nfds: u32, timeout: u32) -> KResult<u32> {
+    do_poll(thread, fds, nfds, timeout).await
 }
 
 #[eonix_macros::define_syscall(SYS_FCHOWNAT)]
-fn fchownat(dirfd: FD, pathname: *const u8, uid: u32, gid: u32, flags: AtFlags) -> KResult<()> {
+async fn fchownat(
+    dirfd: FD,
+    pathname: User<u8>,
+    uid: u32,
+    gid: u32,
+    flags: AtFlags,
+) -> KResult<()> {
     let dentry = dentry_from(thread, dirfd, pathname, !flags.no_follow())?;
     if !dentry.is_valid() {
         return Err(ENOENT);
@@ -579,7 +611,7 @@ fn fchownat(dirfd: FD, pathname: *const u8, uid: u32, gid: u32, flags: AtFlags)
 }
 
 #[eonix_macros::define_syscall(SYS_FCHMODAT)]
-fn fchmodat(dirfd: FD, pathname: *const u8, mode: u32, flags: AtFlags) -> KResult<()> {
+async fn fchmodat(dirfd: FD, pathname: User<u8>, mode: u32, flags: AtFlags) -> KResult<()> {
     let dentry = if flags.at_empty_path() {
         let file = thread.files.get(dirfd).ok_or(EBADF)?;
         file.as_path().ok_or(EBADF)?.clone()
@@ -595,15 +627,15 @@ fn fchmodat(dirfd: FD, pathname: *const u8, mode: u32, flags: AtFlags) -> KResul
 }
 
 #[eonix_macros::define_syscall(SYS_FCHMOD)]
-fn chmod(pathname: *const u8, mode: u32) -> KResult<()> {
-    sys_fchmodat(thread, FD::AT_FDCWD, pathname, mode, AtFlags::empty())
+async fn chmod(pathname: User<u8>, mode: u32) -> KResult<()> {
+    sys_fchmodat(thread, FD::AT_FDCWD, pathname, mode, AtFlags::empty()).await
 }
 
 #[eonix_macros::define_syscall(SYS_UTIMENSAT)]
-fn utimensat(
+async fn utimensat(
     dirfd: FD,
-    pathname: *const u8,
-    times: *const TimeSpec,
+    pathname: User<u8>,
+    times: User<TimeSpec>,
     flags: AtFlags,
 ) -> KResult<()> {
     let dentry = if flags.at_empty_path() {
@@ -630,11 +662,11 @@ fn utimensat(
 }
 
 #[eonix_macros::define_syscall(SYS_RENAMEAT2)]
-fn renameat2(
+async fn renameat2(
     old_dirfd: FD,
-    old_pathname: *const u8,
+    old_pathname: User<u8>,
     new_dirfd: FD,
-    new_pathname: *const u8,
+    new_pathname: User<u8>,
     flags: u32,
 ) -> KResult<()> {
     let flags = RenameFlags::from_bits(flags).ok_or(EINVAL)?;
@@ -652,7 +684,7 @@ fn renameat2(
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_RENAME)]
-fn rename(old_pathname: *const u8, new_pathname: *const u8) -> KResult<()> {
+async fn rename(old_pathname: User<u8>, new_pathname: User<u8>) -> KResult<()> {
     sys_renameat2(
         thread,
         FD::AT_FDCWD,
@@ -661,6 +693,7 @@ fn rename(old_pathname: *const u8, new_pathname: *const u8) -> KResult<()> {
         new_pathname,
         0,
     )
+    .await
 }
 
 pub fn keep_alive() {}

+ 64 - 41
src/kernel/syscall/mm.rs

@@ -2,7 +2,7 @@ use super::FromSyscallArg;
 use crate::fs::shm::{gen_shm_id, ShmFlags, IPC_PRIVATE, SHM_MANAGER};
 use crate::kernel::constants::{EBADF, EEXIST, EINVAL, ENOENT};
 use crate::kernel::mem::FileMapping;
-use crate::kernel::task::{block_on, Thread};
+use crate::kernel::task::Thread;
 use crate::kernel::vfs::filearray::FD;
 use crate::{
     kernel::{
@@ -39,7 +39,7 @@ fn check_impl(condition: bool, err: u32) -> KResult<()> {
     }
 }
 
-fn do_mmap2(
+async fn do_mmap2(
     thread: &Thread,
     addr: usize,
     len: usize,
@@ -67,7 +67,10 @@ fn do_mmap2(
         } else {
             // The mode is unimportant here, since we are checking prot in mm_area.
             let shared_area =
-                block_on(SHM_MANAGER.lock()).create_shared_area(len, thread.process.pid, 0x777);
+                SHM_MANAGER
+                    .lock()
+                    .await
+                    .create_shared_area(len, thread.process.pid, 0x777);
             Mapping::File(FileMapping::new(shared_area.area.clone(), 0, len))
         }
     } else {
@@ -90,10 +93,14 @@ fn do_mmap2(
     // TODO!!!: If we are doing mmap's in 32-bit mode, we should check whether
     //          `addr` is above user reachable memory.
     let addr = if flags.contains(UserMmapFlags::MAP_FIXED) {
-        block_on(mm_list.unmap(addr, len));
-        mm_list.mmap_fixed(addr, len, mapping, permission, is_shared)
+        mm_list.unmap(addr, len).await?;
+        mm_list
+            .mmap_fixed(addr, len, mapping, permission, is_shared)
+            .await
     } else {
-        mm_list.mmap_hint(addr, len, mapping, permission, is_shared)
+        mm_list
+            .mmap_hint(addr, len, mapping, permission, is_shared)
+            .await
     };
 
     addr.map(|addr| addr.addr())
@@ -101,7 +108,7 @@ fn do_mmap2(
 
 #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))]
 #[eonix_macros::define_syscall(SYS_MMAP)]
-fn mmap(
+async fn mmap(
     addr: usize,
     len: usize,
     prot: UserMmapProtocol,
@@ -109,12 +116,12 @@ fn mmap(
     fd: FD,
     offset: usize,
 ) -> KResult<usize> {
-    do_mmap2(thread, addr, len, prot, flags, fd, offset)
+    do_mmap2(thread, addr, len, prot, flags, fd, offset).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_MMAP2)]
-fn mmap2(
+async fn mmap2(
     addr: usize,
     len: usize,
     prot: UserMmapProtocol,
@@ -122,33 +129,33 @@ fn mmap2(
     fd: FD,
     pgoffset: usize,
 ) -> KResult<usize> {
-    do_mmap2(thread, addr, len, prot, flags, fd, pgoffset)
+    do_mmap2(thread, addr, len, prot, flags, fd, pgoffset).await
 }
 
 #[eonix_macros::define_syscall(SYS_MUNMAP)]
-fn munmap(addr: usize, len: usize) -> KResult<usize> {
+async fn munmap(addr: usize, len: usize) -> KResult<()> {
     let addr = VAddr::from(addr);
     if !addr.is_page_aligned() || len == 0 {
         return Err(EINVAL);
     }
 
     let len = len.align_up(PAGE_SIZE);
-    block_on(thread.process.mm_list.unmap(addr, len)).map(|_| 0)
+    thread.process.mm_list.unmap(addr, len).await
 }
 
 #[eonix_macros::define_syscall(SYS_BRK)]
-fn brk(addr: usize) -> KResult<usize> {
+async fn brk(addr: usize) -> KResult<usize> {
     let vaddr = if addr == 0 { None } else { Some(VAddr::from(addr)) };
-    Ok(thread.process.mm_list.set_break(vaddr).addr())
+    Ok(thread.process.mm_list.set_break(vaddr).await.addr())
 }
 
 #[eonix_macros::define_syscall(SYS_MADVISE)]
-fn madvise(_addr: usize, _len: usize, _advice: u32) -> KResult<()> {
+async fn madvise(_addr: usize, _len: usize, _advice: u32) -> KResult<()> {
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_MPROTECT)]
-fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
+async fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
     let addr = VAddr::from(addr);
     if !addr.is_page_aligned() || len == 0 {
         return Err(EINVAL);
@@ -156,22 +163,26 @@ fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
 
     let len = len.align_up(PAGE_SIZE);
 
-    block_on(thread.process.mm_list.protect(
-        addr,
-        len,
-        Permission {
-            read: prot.contains(UserMmapProtocol::PROT_READ),
-            write: prot.contains(UserMmapProtocol::PROT_WRITE),
-            execute: prot.contains(UserMmapProtocol::PROT_EXEC),
-        },
-    ))
+    thread
+        .process
+        .mm_list
+        .protect(
+            addr,
+            len,
+            Permission {
+                read: prot.contains(UserMmapProtocol::PROT_READ),
+                write: prot.contains(UserMmapProtocol::PROT_WRITE),
+                execute: prot.contains(UserMmapProtocol::PROT_EXEC),
+            },
+        )
+        .await
 }
 
 #[eonix_macros::define_syscall(SYS_SHMGET)]
-fn shmget(key: usize, size: usize, shmflg: u32) -> KResult<u32> {
+async fn shmget(key: usize, size: usize, shmflg: u32) -> KResult<u32> {
     let size = size.align_up(PAGE_SIZE);
 
-    let mut shm_manager = block_on(SHM_MANAGER.lock());
+    let mut shm_manager = SHM_MANAGER.lock().await;
     let shmid = gen_shm_id(key)?;
 
     let mode = shmflg & 0o777;
@@ -197,16 +208,17 @@ fn shmget(key: usize, size: usize, shmflg: u32) -> KResult<u32> {
         return Ok(shmid);
     }
 
-    return Err(ENOENT);
+    Err(ENOENT)
 }
 
 #[eonix_macros::define_syscall(SYS_SHMAT)]
-fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
+async fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
     let mm_list = &thread.process.mm_list;
-    let shm_manager = block_on(SHM_MANAGER.lock());
+    let shm_manager = SHM_MANAGER.lock().await;
     let shm_area = shm_manager.get(shmid).ok_or(EINVAL)?;
 
-    let mode = shmflg & 0o777;
+    // Why is this not used?
+    let _mode = shmflg & 0o777;
     let shmflg = ShmFlags::from_bits_truncate(shmflg);
 
     let mut permission = Permission {
@@ -235,9 +247,13 @@ fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
             return Err(EINVAL);
         }
         let addr = VAddr::from(addr.align_down(PAGE_SIZE));
-        mm_list.mmap_fixed(addr, size, mapping, permission, true)
+        mm_list
+            .mmap_fixed(addr, size, mapping, permission, true)
+            .await
     } else {
-        mm_list.mmap_hint(VAddr::NULL, size, mapping, permission, true)
+        mm_list
+            .mmap_hint(VAddr::NULL, size, mapping, permission, true)
+            .await
     }?;
 
     thread.process.shm_areas.lock().insert(addr, size);
@@ -246,22 +262,29 @@ fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_SHMDT)]
-fn shmdt(addr: usize) -> KResult<usize> {
+async fn shmdt(addr: usize) -> KResult<()> {
     let addr = VAddr::from(addr);
-    let mut shm_areas = thread.process.shm_areas.lock();
-    let size = *shm_areas.get(&addr).ok_or(EINVAL)?;
-    shm_areas.remove(&addr);
-    drop(shm_areas);
-    return block_on(thread.process.mm_list.unmap(addr, size)).map(|_| 0);
+
+    let size = {
+        let mut shm_areas = thread.process.shm_areas.lock();
+        let size = *shm_areas.get(&addr).ok_or(EINVAL)?;
+        shm_areas.remove(&addr);
+
+        size
+    };
+
+    thread.process.mm_list.unmap(addr, size).await
 }
 
 #[eonix_macros::define_syscall(SYS_SHMCTL)]
-fn shmctl(shmid: u32, op: i32, shmid_ds: usize) -> KResult<usize> {
+async fn shmctl(_shmid: u32, _op: i32, _shmid_ds: usize) -> KResult<usize> {
+    // TODO
     Ok(0)
 }
 
 #[eonix_macros::define_syscall(SYS_MEMBARRIER)]
-fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
+async fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
+    // TODO
     Ok(())
 }
 

+ 1 - 1
src/kernel/syscall/net.rs

@@ -3,7 +3,7 @@ use crate::prelude::*;
 use posix_types::syscall_no::*;
 
 #[eonix_macros::define_syscall(SYS_SOCKET)]
-fn socket(_domain: u32, _socket_type: u32, _protocol: u32) -> KResult<u32> {
+async fn socket(_domain: u32, _socket_type: u32, _protocol: u32) -> KResult<u32> {
     Err(EINVAL)
 }
 

+ 168 - 180
src/kernel/syscall/procops.rs

@@ -7,26 +7,26 @@ use crate::kernel::constants::{
     ENOSYS, 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::{
-    block_on, do_clone, futex_wait, futex_wake, yield_now, FutexFlags, FutexOp, ProcessList,
-    ProgramLoader, RobustListHead, SignalAction, Thread, WaitId, WaitType,
+    do_clone, futex_wait, futex_wake, yield_now, 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::dataflow::UserString;
+use crate::kernel::user::UserString;
 use crate::kernel::user::{UserPointer, UserPointerMut};
 use crate::kernel::vfs::{self, dentry::Dentry};
 use crate::path::Path;
-use crate::{kernel::user::dataflow::UserBuffer, prelude::*};
+use crate::{kernel::user::UserBuffer, prelude::*};
 use alloc::borrow::ToOwned;
 use alloc::ffi::CString;
 use bitflags::bitflags;
-use core::ptr::NonNull;
 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 _, VAddr};
+use eonix_mm::address::Addr as _;
 use eonix_sync::AsProof as _;
 use posix_types::ctypes::PtrT;
 use posix_types::signal::{SigAction, SigInfo, SigSet, Signal};
@@ -49,7 +49,7 @@ bitflags! {
 }
 
 #[eonix_macros::define_syscall(SYS_NANOSLEEP)]
-fn nanosleep(req: *const (u32, u32), rem: *mut (u32, u32)) -> KResult<usize> {
+async fn nanosleep(req: User<(u32, u32)>, rem: UserMut<(u32, u32)>) -> KResult<usize> {
     let req = UserPointer::new(req)?.read()?;
     let rem = if rem.is_null() {
         None
@@ -58,7 +58,7 @@ fn nanosleep(req: *const (u32, u32), rem: *mut (u32, u32)) -> KResult<usize> {
     };
 
     let duration = Duration::from_secs(req.0 as u64) + Duration::from_nanos(req.1 as u64);
-    block_on(sleep(duration));
+    sleep(duration).await;
 
     if let Some(rem) = rem {
         rem.write((0, 0))?;
@@ -68,11 +68,11 @@ fn nanosleep(req: *const (u32, u32), rem: *mut (u32, u32)) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_CLOCK_NANOSLEEP)]
-fn clock_nanosleep(
+async fn clock_nanosleep(
     clock_id: u32,
-    flags: u32,
-    req: *const (u32, u32),
-    rem: *mut (u32, u32),
+    _flags: u32,
+    req: User<(u32, u32)>,
+    rem: UserMut<(u32, u32)>,
 ) -> KResult<usize> {
     if clock_id != CLOCK_REALTIME
         && clock_id != CLOCK_REALTIME_COARSE
@@ -89,7 +89,7 @@ fn clock_nanosleep(
     };
 
     let duration = Duration::from_secs(req.0 as u64) + Duration::from_nanos(req.1 as u64);
-    block_on(sleep(duration));
+    sleep(duration).await;
 
     if let Some(rem) = rem {
         rem.write((0, 0))?;
@@ -99,7 +99,7 @@ fn clock_nanosleep(
 }
 
 #[eonix_macros::define_syscall(SYS_UMASK)]
-fn umask(mask: u32) -> KResult<u32> {
+async fn umask(mask: u32) -> KResult<u32> {
     let mut umask = thread.fs_context.umask.lock();
 
     let old = *umask;
@@ -108,7 +108,7 @@ fn umask(mask: u32) -> KResult<u32> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETCWD)]
-fn getcwd(buffer: *mut u8, bufsize: usize) -> KResult<usize> {
+async fn getcwd(buffer: UserMut<u8>, bufsize: usize) -> KResult<usize> {
     let mut user_buffer = UserBuffer::new(buffer, bufsize)?;
     let mut buffer = PageBuffer::new();
 
@@ -121,7 +121,7 @@ fn getcwd(buffer: *mut u8, bufsize: usize) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(SYS_CHDIR)]
-fn chdir(path: *const u8) -> KResult<()> {
+async fn chdir(path: User<u8>) -> KResult<()> {
     let path = UserString::new(path)?;
     let path = Path::new(path.as_cstr().to_bytes())?;
 
@@ -139,7 +139,7 @@ fn chdir(path: *const u8) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_UMOUNT)]
-fn umount(source: *const u8) -> KResult<()> {
+async fn umount(source: User<u8>) -> KResult<()> {
     let source = UserString::new(source)?;
     if source.as_cstr().to_str().unwrap() == "./mnt" {
         return Ok(());
@@ -148,7 +148,7 @@ fn umount(source: *const u8) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_MOUNT)]
-fn mount(source: *const u8, target: *const u8, fstype: *const u8, flags: usize) -> KResult<()> {
+async fn mount(source: User<u8>, target: User<u8>, fstype: User<u8>, flags: usize) -> KResult<()> {
     let source = UserString::new(source)?;
     if source.as_cstr().to_str().unwrap() == "/dev/vda2" {
         return Ok(());
@@ -184,7 +184,7 @@ fn get_strings(mut ptr_strings: UserPointer<'_, PtrT>) -> KResult<Vec<CString>>
             break;
         }
 
-        let user_string = UserString::new(ptr.addr() as *const u8)?;
+        let user_string = UserString::new(User::with_addr(ptr.addr()))?;
         strings.push(user_string.as_cstr().to_owned());
         ptr_strings = ptr_strings.offset(1)?;
     }
@@ -193,7 +193,7 @@ fn get_strings(mut ptr_strings: UserPointer<'_, PtrT>) -> KResult<Vec<CString>>
 }
 
 #[eonix_macros::define_syscall(SYS_EXECVE)]
-fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<SyscallNoReturn> {
+async fn execve(exec: User<u8>, argv: User<PtrT>, envp: User<PtrT>) -> KResult<SyscallNoReturn> {
     let exec = UserString::new(exec)?;
     let exec = exec.as_cstr().to_owned();
 
@@ -207,11 +207,12 @@ fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<Sysc
 
     // TODO: When `execve` is called by one of the threads in a process, the other threads
     //       should be terminated and `execve` is performed in the thread group leader.
-    let load_info =
-        ProgramLoader::parse(&thread.fs_context, exec, dentry.clone(), argv, envp)?.load()?;
+    let load_info = ProgramLoader::parse(&thread.fs_context, exec, dentry.clone(), argv, envp)?
+        .load()
+        .await?;
 
     if let Some(robust_list) = thread.get_robust_list() {
-        let _ = block_on(robust_list.wake_all());
+        let _ = robust_list.wake_all().await;
         thread.set_robust_list(None);
     }
 
@@ -236,37 +237,41 @@ fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<Sysc
 }
 
 #[eonix_macros::define_syscall(SYS_EXIT)]
-fn exit(status: u32) -> SyscallNoReturn {
+async fn exit(status: u32) -> SyscallNoReturn {
+    let mut procs = ProcessList::get().write().await;
+
     unsafe {
-        let mut procs = block_on(ProcessList::get().write());
-        block_on(procs.do_exit(&thread, WaitType::Exited(status), false));
+        procs
+            .do_exit(&thread, WaitType::Exited(status), false)
+            .await;
     }
 
     SyscallNoReturn
 }
 
 #[eonix_macros::define_syscall(SYS_EXIT_GROUP)]
-fn exit_group(status: u32) -> SyscallNoReturn {
+async fn exit_group(status: u32) -> SyscallNoReturn {
+    let mut procs = ProcessList::get().write().await;
+
     unsafe {
-        let mut procs = block_on(ProcessList::get().write());
-        block_on(procs.do_exit(&thread, WaitType::Exited(status), true));
+        procs.do_exit(&thread, WaitType::Exited(status), true).await;
     }
 
     SyscallNoReturn
 }
 
 enum WaitInfo {
-    SigInfo(NonNull<SigInfo>),
-    Status(NonNull<u32>),
+    SigInfo(UserMut<SigInfo>),
+    Status(UserMut<u32>),
     None,
 }
 
-fn do_waitid(
+async fn do_waitid(
     thread: &Thread,
     wait_id: WaitId,
     info: WaitInfo,
     options: u32,
-    rusage: *mut RUsage,
+    rusage: UserMut<RUsage>,
 ) -> KResult<u32> {
     if !rusage.is_null() {
         unimplemented!("waitid with rusage pointer");
@@ -277,12 +282,15 @@ fn do_waitid(
         Some(options) => options,
     };
 
-    let Some(wait_object) = block_on(thread.process.wait(
-        wait_id,
-        options.contains(UserWaitOptions::WNOHANG),
-        options.contains(UserWaitOptions::WUNTRACED),
-        options.contains(UserWaitOptions::WCONTINUED),
-    ))?
+    let Some(wait_object) = thread
+        .process
+        .wait(
+            wait_id,
+            options.contains(UserWaitOptions::WNOHANG),
+            options.contains(UserWaitOptions::WUNTRACED),
+            options.contains(UserWaitOptions::WCONTINUED),
+        )
+        .await?
     else {
         return Ok(0);
     };
@@ -298,11 +306,11 @@ fn do_waitid(
             siginfo.si_status = status;
             siginfo.si_code = code;
 
-            UserPointerMut::new(siginfo_ptr.as_ptr())?.write(siginfo)?;
+            UserPointerMut::new(siginfo_ptr)?.write(siginfo)?;
             Ok(0)
         }
         WaitInfo::Status(status_ptr) => {
-            UserPointerMut::new(status_ptr.as_ptr())?.write(wait_object.code.to_wstatus())?;
+            UserPointerMut::new(status_ptr)?.write(wait_object.code.to_wstatus())?;
             Ok(wait_object.pid)
         }
         WaitInfo::None => Ok(wait_object.pid),
@@ -310,18 +318,16 @@ fn do_waitid(
 }
 
 #[eonix_macros::define_syscall(SYS_WAITID)]
-fn waitid(
+async fn waitid(
     id_type: u32,
     id: u32,
-    info: *mut SigInfo,
+    info: UserMut<SigInfo>,
     options: u32,
-    rusage: *mut RUsage,
+    rusage: UserMut<RUsage>,
 ) -> KResult<u32> {
     let wait_id = WaitId::from_type_and_id(id_type, id)?;
 
-    if let Some(info) = NonNull::new(info) {
-        do_waitid(thread, wait_id, WaitInfo::SigInfo(info), options, rusage)
-    } else {
+    if info.is_null() {
         /*
          * According to POSIX.1-2008, an application calling waitid() must
          * ensure that infop points to a siginfo_t structure (i.e., that it
@@ -332,34 +338,41 @@ fn waitid(
          */
         unimplemented!("waitid with null info pointer");
     }
+
+    do_waitid(thread, wait_id, WaitInfo::SigInfo(info), options, rusage).await
 }
 
 #[eonix_macros::define_syscall(SYS_WAIT4)]
-fn wait4(wait_id: i32, arg1: *mut u32, options: u32, rusage: *mut RUsage) -> KResult<u32> {
-    let waitinfo = if let Some(status) = NonNull::new(arg1) {
-        WaitInfo::Status(status)
-    } else {
+async fn wait4(
+    wait_id: i32,
+    arg1: UserMut<u32>,
+    options: u32,
+    rusage: UserMut<RUsage>,
+) -> KResult<u32> {
+    let waitinfo = if arg1.is_null() {
         WaitInfo::None
+    } else {
+        WaitInfo::Status(arg1)
     };
 
     let wait_id = WaitId::from_id(wait_id, thread);
 
-    do_waitid(thread, wait_id, waitinfo, options, rusage)
+    do_waitid(thread, wait_id, waitinfo, options, rusage).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_WAITPID)]
-fn waitpid(waitpid: i32, arg1: *mut u32, options: u32) -> KResult<u32> {
-    sys_wait4(thread, waitpid, arg1, options, core::ptr::null_mut())
+async fn waitpid(waitpid: i32, arg1: UserMut<u32>, options: u32) -> KResult<u32> {
+    sys_wait4(thread, waitpid, arg1, options, core::ptr::null_mut()).await
 }
 
 #[eonix_macros::define_syscall(SYS_SETSID)]
-fn setsid() -> KResult<u32> {
-    thread.process.setsid()
+async fn setsid() -> KResult<u32> {
+    thread.process.setsid().await
 }
 
 #[eonix_macros::define_syscall(SYS_SETPGID)]
-fn setpgid(pid: u32, pgid: i32) -> KResult<()> {
+async fn setpgid(pid: u32, pgid: i32) -> KResult<()> {
     let pid = if pid == 0 { thread.process.pid } else { pid };
 
     let pgid = match pgid {
@@ -368,15 +381,15 @@ fn setpgid(pid: u32, pgid: i32) -> KResult<()> {
         _ => return Err(EINVAL),
     };
 
-    thread.process.setpgid(pid, pgid)
+    thread.process.setpgid(pid, pgid).await
 }
 
 #[eonix_macros::define_syscall(SYS_GETSID)]
-fn getsid(pid: u32) -> KResult<u32> {
+async fn getsid(pid: u32) -> KResult<u32> {
     if pid == 0 {
         Ok(thread.process.session_rcu().sid)
     } else {
-        let procs = block_on(ProcessList::get().read());
+        let procs = ProcessList::get().read().await;
         procs
             .try_find_process(pid)
             .map(|proc| proc.session(procs.prove()).sid)
@@ -385,11 +398,11 @@ fn getsid(pid: u32) -> KResult<u32> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETPGID)]
-fn getpgid(pid: u32) -> KResult<u32> {
+async fn getpgid(pid: u32) -> KResult<u32> {
     if pid == 0 {
         Ok(thread.process.pgroup_rcu().pgid)
     } else {
-        let procs = block_on(ProcessList::get().read());
+        let procs = ProcessList::get().read().await;
         procs
             .try_find_process(pid)
             .map(|proc| proc.pgroup(procs.prove()).pgid)
@@ -398,12 +411,12 @@ fn getpgid(pid: u32) -> KResult<u32> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETPID)]
-fn getpid() -> KResult<u32> {
+async fn getpid() -> KResult<u32> {
     Ok(thread.process.pid)
 }
 
 #[eonix_macros::define_syscall(SYS_GETPPID)]
-fn getppid() -> KResult<u32> {
+async fn getppid() -> KResult<u32> {
     Ok(thread.process.parent_rcu().map_or(0, |x| x.pid))
 }
 
@@ -419,78 +432,61 @@ fn do_getuid(_thread: &Thread) -> KResult<u32> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_GETUID32)]
-fn getuid32() -> KResult<u32> {
+async fn getuid32() -> KResult<u32> {
     do_getuid(thread)
 }
 
 #[eonix_macros::define_syscall(SYS_GETUID)]
-fn getuid() -> KResult<u32> {
+async fn getuid() -> KResult<u32> {
     do_getuid(thread)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_GETEUID32)]
-fn geteuid32() -> KResult<u32> {
+async fn geteuid32() -> KResult<u32> {
     do_geteuid(thread)
 }
 
 #[eonix_macros::define_syscall(SYS_GETEUID)]
-fn geteuid() -> KResult<u32> {
+async fn geteuid() -> KResult<u32> {
     do_geteuid(thread)
 }
 
 #[eonix_macros::define_syscall(SYS_GETEGID)]
-fn getegid() -> KResult<u32> {
+async fn getegid() -> KResult<u32> {
     // All users are root for now.
     Ok(0)
 }
 
 #[eonix_macros::define_syscall(SYS_GETGID)]
-fn getgid() -> KResult<u32> {
-    sys_getegid(thread)
+async fn getgid() -> KResult<u32> {
+    sys_getegid(thread).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_GETGID32)]
-fn getgid32() -> KResult<u32> {
-    sys_getegid(thread)
-}
-
-#[eonix_macros::define_syscall(SYS_GETRANDOM)]
-fn getrandom(buf: *mut u8, buflen: usize, _flags: u32) -> isize {
-    if buf.is_null() || buflen == 0 {
-        return -14;
-    }
-
-    static mut SEED: u64 = 1;
-    unsafe {
-        for i in 0..buflen {
-            SEED = SEED.wrapping_mul(1103515245).wrapping_add(12345);
-            *buf.add(i) = (SEED >> 8) as u8;
-        }
-    }
-
-    buflen as isize
+async fn getgid32() -> KResult<u32> {
+    sys_getegid(thread).await
 }
 
 #[eonix_macros::define_syscall(SYS_SCHED_YIELD)]
-fn sched_yield() -> KResult<()> {
-    block_on(yield_now());
+async fn sched_yield() -> KResult<()> {
+    yield_now().await;
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_SYNC)]
-fn sync() -> KResult<()> {
+async fn sync() -> KResult<()> {
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_FSYNC)]
-fn fsync() -> KResult<()> {
+async fn fsync() -> KResult<()> {
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_GETTID)]
-fn gettid() -> KResult<u32> {
+async fn gettid() -> KResult<u32> {
     Ok(thread.tid)
 }
 
@@ -530,7 +526,7 @@ pub fn parse_user_tls(arch_tls: usize) -> KResult<UserTLS> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SET_THREAD_AREA)]
-fn set_thread_area(arch_tls: usize) -> KResult<()> {
+async fn set_thread_area(arch_tls: usize) -> KResult<()> {
     thread.set_user_tls(parse_user_tls(arch_tls)?)?;
 
     // SAFETY: Preemption is disabled on calling `load_thread_area32()`.
@@ -544,16 +540,16 @@ fn set_thread_area(arch_tls: usize) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_SET_TID_ADDRESS)]
-fn set_tid_address(tidptr: usize) -> KResult<u32> {
+async fn set_tid_address(tidptr: UserMut<u32>) -> KResult<u32> {
     thread.clear_child_tid(Some(tidptr));
     Ok(thread.tid)
 }
 
 #[eonix_macros::define_syscall(SYS_PRCTL)]
-fn prctl(option: u32, arg2: usize) -> KResult<()> {
+async fn prctl(option: u32, arg2: PtrT) -> KResult<()> {
     match option {
         PR_SET_NAME => {
-            let name = UserPointer::new(arg2 as *mut [u8; 16])?.read()?;
+            let name = UserPointer::<[u8; 16]>::new(User::with_addr(arg2.addr()))?.read()?;
             let len = name.iter().position(|&c| c == 0).unwrap_or(15);
             thread.set_name(name[..len].into());
             Ok(())
@@ -562,7 +558,7 @@ fn prctl(option: u32, arg2: usize) -> KResult<()> {
             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::new(arg2 as *mut [u8; 16])?.write(name)?;
+            UserPointerMut::<[u8; 16]>::new(UserMut::with_addr(arg2.addr()))?.write(name)?;
             Ok(())
         }
         _ => Err(EINVAL),
@@ -570,8 +566,8 @@ fn prctl(option: u32, arg2: usize) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_KILL)]
-fn kill(pid: i32, sig: u32) -> KResult<()> {
-    let procs = block_on(ProcessList::get().read());
+async fn kill(pid: i32, sig: u32) -> KResult<()> {
+    let procs = ProcessList::get().read().await;
     match pid {
         // Send signal to every process for which the calling process has
         // permission to send signals.
@@ -597,8 +593,10 @@ fn kill(pid: i32, sig: u32) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_TKILL)]
-fn tkill(tid: u32, sig: u32) -> KResult<()> {
-    block_on(ProcessList::get().read())
+async fn tkill(tid: u32, sig: u32) -> KResult<()> {
+    ProcessList::get()
+        .read()
+        .await
         .try_find_thread(tid)
         .ok_or(ESRCH)?
         .raise(Signal::try_from_raw(sig)?);
@@ -606,8 +604,8 @@ fn tkill(tid: u32, sig: u32) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_TGKILL)]
-fn tgkill(tgid: u32, tid: u32, sig: u32) -> KResult<()> {
-    let procs = block_on(ProcessList::get().read());
+async fn tgkill(tgid: u32, tid: u32, sig: u32) -> KResult<()> {
+    let procs = ProcessList::get().read().await;
 
     let thread_to_kill = procs.try_find_thread(tid).ok_or(ESRCH)?;
     if thread_to_kill.process.pid != tgid {
@@ -619,10 +617,10 @@ fn tgkill(tgid: u32, tid: u32, sig: u32) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_RT_SIGPROCMASK)]
-fn rt_sigprocmask(
+async fn rt_sigprocmask(
     how: u32,
-    set: *mut SigSet,
-    oldset: *mut SigSet,
+    set: UserMut<SigSet>,
+    oldset: UserMut<SigSet>,
     sigsetsize: usize,
 ) -> KResult<()> {
     if sigsetsize != size_of::<SigSet>() {
@@ -635,7 +633,7 @@ fn rt_sigprocmask(
     }
 
     let new_mask = if !set.is_null() {
-        UserPointer::new(set)?.read()?
+        UserPointer::new(set.as_const())?.read()?
     } else {
         return Ok(());
     };
@@ -657,27 +655,21 @@ struct TimeSpec32 {
     tv_nsec: i32,
 }
 
-impl TimeSpec32 {
-    fn to_duration(&self) -> Duration {
-        Duration::new(self.tv_sec as u64, self.tv_nsec as u32)
-    }
-}
-
 #[eonix_macros::define_syscall(SYS_RT_SIGTIMEDWAIT_TIME32)]
-fn rt_sigtimedwait_time32(
-    _uthese: *const SigSet,
-    _uinfo: *mut SigInfo,
-    _uts: *const TimeSpec32,
+async fn rt_sigtimedwait_time32(
+    _uthese: User<SigSet>,
+    _uinfo: UserMut<SigInfo>,
+    _uts: User<TimeSpec32>,
 ) -> KResult<i32> {
     // TODO
     Ok(0)
 }
 
 #[eonix_macros::define_syscall(SYS_RT_SIGACTION)]
-fn rt_sigaction(
+async fn rt_sigaction(
     signum: u32,
-    act: *const SigAction,
-    oldact: *mut SigAction,
+    act: User<SigAction>,
+    oldact: UserMut<SigAction>,
     sigsetsize: usize,
 ) -> KResult<()> {
     let signal = Signal::try_from_raw(signum)?;
@@ -706,11 +698,11 @@ fn rt_sigaction(
 }
 
 #[eonix_macros::define_syscall(SYS_PRLIMIT64)]
-fn prlimit64(
+async fn prlimit64(
     pid: u32,
     resource: u32,
-    new_limit: *const RLimit,
-    old_limit: *mut RLimit,
+    new_limit: User<RLimit>,
+    old_limit: UserMut<RLimit>,
 ) -> KResult<()> {
     if pid != 0 {
         return Err(ENOSYS);
@@ -742,13 +734,13 @@ fn prlimit64(
 }
 
 #[eonix_macros::define_syscall(SYS_GETRLIMIT)]
-fn getrlimit(resource: u32, rlimit: *mut RLimit) -> KResult<()> {
-    sys_prlimit64(thread, 0, resource, core::ptr::null(), rlimit)
+async fn getrlimit(resource: u32, rlimit: UserMut<RLimit>) -> KResult<()> {
+    sys_prlimit64(thread, 0, resource, User::null(), rlimit).await
 }
 
 #[eonix_macros::define_syscall(SYS_SETRLIMIT)]
-fn setrlimit(resource: u32, rlimit: *const RLimit) -> KResult<()> {
-    sys_prlimit64(thread, 0, resource, rlimit, core::ptr::null_mut())
+async fn setrlimit(resource: u32, rlimit: User<RLimit>) -> KResult<()> {
+    sys_prlimit64(thread, 0, resource, rlimit, UserMut::null()).await
 }
 
 #[repr(C)]
@@ -773,7 +765,7 @@ struct RUsage {
 }
 
 #[eonix_macros::define_syscall(SYS_GETRUSAGE)]
-fn getrusage(who: u32, rusage: *mut RUsage) -> KResult<()> {
+async fn getrusage(who: u32, rusage: UserMut<RUsage>) -> KResult<()> {
     if who != 0 {
         return Err(ENOSYS);
     }
@@ -803,52 +795,52 @@ fn getrusage(who: u32, rusage: *mut RUsage) -> KResult<()> {
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_VFORK)]
-fn vfork() -> KResult<u32> {
+async fn vfork() -> KResult<u32> {
     let clone_args = CloneArgs::for_vfork();
 
-    do_clone(thread, clone_args)
+    do_clone(thread, clone_args).await
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_FORK)]
-fn fork() -> KResult<u32> {
+async fn fork() -> KResult<u32> {
     let clone_args = CloneArgs::for_fork();
 
-    do_clone(thread, clone_args)
+    do_clone(thread, clone_args).await
 }
 
 // Some old platforms including x86_32, riscv and arm have the last two arguments
 // swapped, so we need to define two versions of `clone` syscall.
 #[cfg(not(target_arch = "loongarch64"))]
 #[eonix_macros::define_syscall(SYS_CLONE)]
-fn clone(
+async fn clone(
     clone_flags: usize,
     new_sp: usize,
-    parent_tidptr: usize,
+    parent_tidptr: UserMut<u32>,
     tls: usize,
-    child_tidptr: usize,
+    child_tidptr: UserMut<u32>,
 ) -> KResult<u32> {
     let clone_args = CloneArgs::for_clone(clone_flags, new_sp, child_tidptr, parent_tidptr, tls)?;
 
-    do_clone(thread, clone_args)
+    do_clone(thread, clone_args).await
 }
 
 #[cfg(target_arch = "loongarch64")]
 #[eonix_macros::define_syscall(SYS_CLONE)]
-fn clone(
+async fn clone(
     clone_flags: usize,
     new_sp: usize,
-    parent_tidptr: usize,
-    child_tidptr: usize,
+    parent_tidptr: UserMut<u32>,
+    child_tidptr: UserMut<u32>,
     tls: usize,
 ) -> KResult<u32> {
     let clone_args = CloneArgs::for_clone(clone_flags, new_sp, child_tidptr, parent_tidptr, tls)?;
 
-    do_clone(thread, clone_args)
+    do_clone(thread, clone_args).await
 }
 
 #[eonix_macros::define_syscall(SYS_FUTEX)]
-fn futex(
+async fn futex(
     uaddr: usize,
     op: u32,
     val: u32,
@@ -866,11 +858,11 @@ fn futex(
 
     match futex_op {
         FutexOp::FUTEX_WAIT => {
-            block_on(futex_wait(uaddr, pid, val as u32, None))?;
+            futex_wait(uaddr, pid, val as u32, None).await?;
             return Ok(0);
         }
         FutexOp::FUTEX_WAKE => {
-            return block_on(futex_wake(uaddr, pid, val as u32));
+            return futex_wake(uaddr, pid, val as u32).await;
         }
         FutexOp::FUTEX_REQUEUE => {
             todo!()
@@ -882,60 +874,56 @@ fn futex(
 }
 
 #[eonix_macros::define_syscall(SYS_SET_ROBUST_LIST)]
-fn set_robust_list(head: usize, len: usize) -> KResult<()> {
+async fn set_robust_list(head: User<RobustListHead>, len: usize) -> KResult<()> {
     if len != size_of::<RobustListHead>() {
         return Err(EINVAL);
     }
 
-    thread.set_robust_list(Some(VAddr::from(head)));
+    thread.set_robust_list(Some(head));
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_RT_SIGRETURN)]
-fn rt_sigreturn() -> KResult<SyscallNoReturn> {
-    thread
-        .signal_list
-        .restore(
-            &mut thread.trap_ctx.borrow(),
-            &mut thread.fpu_state.borrow(),
-            false,
-        )
-        .inspect_err(|err| {
-            println_warn!(
-                "`rt_sigreturn` failed in thread {} with error {err}!",
-                thread.tid
-            );
-            block_on(thread.force_kill(Signal::SIGSEGV));
-        })?;
+async fn rt_sigreturn() -> KResult<SyscallNoReturn> {
+    if let Err(err) = thread.signal_list.restore(
+        &mut thread.trap_ctx.borrow(),
+        &mut thread.fpu_state.borrow(),
+        false,
+    ) {
+        println_warn!(
+            "`rt_sigreturn` failed in thread {} with error {err}!",
+            thread.tid
+        );
+        thread.force_kill(Signal::SIGSEGV).await;
+        return Err(err);
+    }
 
     Ok(SyscallNoReturn)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SIGRETURN)]
-fn sigreturn() -> KResult<SyscallNoReturn> {
-    thread
-        .signal_list
-        .restore(
-            &mut thread.trap_ctx.borrow(),
-            &mut thread.fpu_state.borrow(),
-            true,
-        )
-        .inspect_err(|err| {
-            println_warn!(
-                "`sigreturn` failed in thread {} with error {err}!",
-                thread.tid
-            );
-            block_on(thread.force_kill(Signal::SIGSEGV));
-        })?;
+async fn sigreturn() -> KResult<SyscallNoReturn> {
+    if let Err(err) = thread.signal_list.restore(
+        &mut thread.trap_ctx.borrow(),
+        &mut thread.fpu_state.borrow(),
+        true,
+    ) {
+        println_warn!(
+            "`sigreturn` failed in thread {} with error {err}!",
+            thread.tid
+        );
+        thread.force_kill(Signal::SIGSEGV).await;
+        return Err(err);
+    }
 
     Ok(SyscallNoReturn)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_ARCH_PRCTL)]
-fn arch_prctl(option: u32, addr: u32) -> KResult<u32> {
-    sys_arch_prctl(thread, option, addr)
+async fn arch_prctl(option: u32, addr: u32) -> KResult<u32> {
+    sys_arch_prctl(thread, option, addr).await
 }
 
 pub fn keep_alive() {}

+ 9 - 8
src/kernel/syscall/sysinfo.rs

@@ -2,6 +2,7 @@ use crate::{
     io::Buffer as _,
     kernel::{
         constants::{CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_REALTIME_COARSE, EINTR, EINVAL},
+        syscall::UserMut,
         task::Thread,
         timer::{Instant, Ticks},
         user::{UserBuffer, UserPointerMut},
@@ -30,7 +31,7 @@ fn copy_cstr_to_array(cstr: &[u8], array: &mut [u8]) {
 }
 
 #[eonix_macros::define_syscall(SYS_NEWUNAME)]
-fn newuname(buffer: *mut NewUTSName) -> KResult<()> {
+async fn newuname(buffer: UserMut<NewUTSName>) -> KResult<()> {
     let buffer = UserPointerMut::new(buffer)?;
     let mut uname = NewUTSName {
         sysname: [0; 65],
@@ -62,7 +63,7 @@ fn newuname(buffer: *mut NewUTSName) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETTIMEOFDAY)]
-fn gettimeofday(timeval: *mut TimeVal, timezone: *mut ()) -> KResult<()> {
+async fn gettimeofday(timeval: UserMut<TimeVal>, timezone: UserMut<()>) -> KResult<()> {
     if !timezone.is_null() {
         return Err(EINVAL);
     }
@@ -81,7 +82,7 @@ fn gettimeofday(timeval: *mut TimeVal, timezone: *mut ()) -> KResult<()> {
     Ok(())
 }
 
-fn do_clock_gettime64(_thread: &Thread, clock_id: u32, timespec: *mut TimeSpec) -> KResult<()> {
+fn do_clock_gettime64(_thread: &Thread, clock_id: u32, timespec: UserMut<TimeSpec>) -> KResult<()> {
     let timespec = UserPointerMut::new(timespec)?;
 
     match clock_id {
@@ -106,13 +107,13 @@ fn do_clock_gettime64(_thread: &Thread, clock_id: u32, timespec: *mut TimeSpec)
 
 #[cfg(not(target_arch = "x86_64"))]
 #[eonix_macros::define_syscall(SYS_CLOCK_GETTIME)]
-fn clock_gettime(clock_id: u32, timespec: *mut TimeSpec) -> KResult<()> {
+async fn clock_gettime(clock_id: u32, timespec: UserMut<TimeSpec>) -> KResult<()> {
     do_clock_gettime64(thread, clock_id, timespec)
 }
 
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_CLOCK_GETTIME64)]
-fn clock_gettime64(clock_id: u32, timespec: *mut TimeSpec) -> KResult<()> {
+async fn clock_gettime64(clock_id: u32, timespec: UserMut<TimeSpec>) -> KResult<()> {
     do_clock_gettime64(thread, clock_id, timespec)
 }
 
@@ -135,7 +136,7 @@ struct Sysinfo {
 }
 
 #[eonix_macros::define_syscall(SYS_SYSINFO)]
-fn sysinfo(info: *mut Sysinfo) -> KResult<()> {
+async fn sysinfo(info: UserMut<Sysinfo>) -> KResult<()> {
     let info = UserPointerMut::new(info)?;
     info.write(Sysinfo {
         uptime: Ticks::since_boot().as_secs() as u32,
@@ -164,7 +165,7 @@ struct TMS {
 }
 
 #[eonix_macros::define_syscall(SYS_TIMES)]
-fn times(tms: *mut TMS) -> KResult<()> {
+async fn times(tms: UserMut<TMS>) -> KResult<()> {
     let tms = UserPointerMut::new(tms)?;
     tms.write(TMS {
         tms_utime: 0,
@@ -175,7 +176,7 @@ fn times(tms: *mut TMS) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_GETRANDOM)]
-fn get_random(buf: *mut u8, len: usize, flags: u32) -> KResult<usize> {
+async fn get_random(buf: UserMut<u8>, len: usize, flags: u32) -> KResult<usize> {
     if flags != 0 {
         return Err(EINVAL);
     }

+ 10 - 10
src/kernel/task/clone.rs

@@ -1,7 +1,6 @@
-use super::block_on;
 use crate::{
     kernel::{
-        syscall::procops::parse_user_tls,
+        syscall::{procops::parse_user_tls, UserMut},
         task::{alloc_pid, ProcessBuilder, ProcessList, Thread, ThreadBuilder},
         user::UserPointerMut,
     },
@@ -49,9 +48,9 @@ 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<usize>, // Pointer to set child TID in user space.
-    pub clear_tid_ptr: Option<usize>, // Pointer to clear child TID in user space.
-    pub parent_tid_ptr: Option<usize>, // Pointer to parent TID in user space.
+    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.
 }
 
@@ -61,8 +60,8 @@ impl CloneArgs {
     pub fn for_clone(
         flags: usize,
         sp: usize,
-        child_tid_ptr: usize,
-        parent_tid_ptr: usize,
+        child_tid_ptr: UserMut<u32>,
+        parent_tid_ptr: UserMut<u32>,
         tls: usize,
     ) -> KResult<Self> {
         let clone_flags = CloneFlags::from_bits_truncate(flags & !Self::MASK);
@@ -131,8 +130,8 @@ impl CloneArgs {
     }
 }
 
-pub fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
-    let mut procs = block_on(ProcessList::get().write());
+pub async fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
+    let mut procs = ProcessList::get().write().await;
 
     let thread_builder = ThreadBuilder::new().clone_from(&thread, &clone_args)?;
     let current_process = thread.process.clone();
@@ -152,6 +151,7 @@ pub fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
 
         let (new_thread, _) = ProcessBuilder::new()
             .clone_from(current_process, &clone_args)
+            .await
             .pid(new_pid)
             .pgroup(current_pgroup)
             .session(current_session)
@@ -161,7 +161,7 @@ pub fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
     };
 
     if let Some(parent_tid_ptr) = clone_args.parent_tid_ptr {
-        UserPointerMut::new(parent_tid_ptr as *mut u32)?.write(new_pid)?
+        UserPointerMut::new(parent_tid_ptr)?.write(new_pid)?
     }
 
     RUNTIME.spawn(new_thread.run());

+ 7 - 6
src/kernel/task/futex.rs

@@ -9,6 +9,7 @@ use intrusive_collections::{intrusive_adapter, KeyAdapter, RBTree, RBTreeAtomicL
 use crate::{
     kernel::{
         constants::{EAGAIN, EINVAL},
+        syscall::User,
         user::UserPointer,
     },
     prelude::KResult,
@@ -174,7 +175,7 @@ pub async fn futex_wait(
         let (_, futex_bucket_ref) = FUTEX_TABLE.get_bucket(&futex_key);
         let mut futex_bucket = futex_bucket_ref.lock().await;
 
-        let val = UserPointer::new(uaddr as *const u32)?.read()?;
+        let val = UserPointer::new(User::<u32>::with_addr(uaddr))?.read()?;
 
         if val != expected_val {
             return Err(EAGAIN);
@@ -238,20 +239,20 @@ async fn futex_requeue(
     pid: Option<u32>,
     wake_count: u32,
     requeue_uaddr: usize,
-    requeue_count: u32,
+    _requeue_count: u32,
 ) -> KResult<usize> {
     let futex_key = FutexKey::new(uaddr, pid);
     let futex_requeue_key = FutexKey::new(requeue_uaddr, pid);
 
-    let (bucket_idx0, bucket_ref0) = FUTEX_TABLE.get_bucket(&futex_key);
-    let (bucket_idx1, bucket_ref1) = FUTEX_TABLE.get_bucket(&futex_requeue_key);
+    let (bucket_idx0, _bucket_ref0) = FUTEX_TABLE.get_bucket(&futex_key);
+    let (bucket_idx1, _bucket_ref1) = FUTEX_TABLE.get_bucket(&futex_requeue_key);
 
     if bucket_idx0 == bucket_idx1 {
         // If the keys are the same, we can just wake up the waiters.
         return futex_wake(uaddr, pid, wake_count).await;
     }
 
-    let (futex_bucket, futex_requeue_bucket) =
+    let (_futex_bucket, _futex_requeue_bucket) =
         double_lock_bucket(futex_key, futex_requeue_key).await;
 
     todo!()
@@ -299,7 +300,7 @@ impl RobustListHead {
             futex_wake(futex_addr, None, usize::MAX as u32).await?;
 
             // Move to the next entry in the robust list.
-            let robust_list = UserPointer::new(entry_ptr as *const RobustList)?.read()?;
+            let robust_list = UserPointer::new(User::<RobustList>::with_addr(entry_ptr))?.read()?;
 
             entry_ptr = robust_list.next;
 

+ 103 - 86
src/kernel/task/loader/elf.rs

@@ -215,20 +215,20 @@ impl<E: ElfArch> Elf<E> {
         })
     }
 
-    fn load(&self, args: Vec<CString>, envs: Vec<CString>) -> KResult<LoadInfo> {
+    async fn load(&self, args: Vec<CString>, envs: Vec<CString>) -> KResult<LoadInfo> {
         let mm_list = MMList::new();
 
         // Load Segments
-        let (elf_base, data_segment_end) = self.load_segments(&mm_list)?;
+        let (elf_base, data_segment_end) = self.load_segments(&mm_list).await?;
 
         // Load ldso (if any)
-        let ldso_load_info = self.load_ldso(&mm_list)?;
+        let ldso_load_info = self.load_ldso(&mm_list).await?;
 
         // Load vdso
-        self.load_vdso(&mm_list)?;
+        self.load_vdso(&mm_list).await?;
 
         // Heap
-        mm_list.register_break(data_segment_end + 0x10000);
+        mm_list.register_break(data_segment_end + 0x10000).await;
 
         let aux_vec = self.init_aux_vec(
             elf_base,
@@ -238,7 +238,9 @@ impl<E: ElfArch> Elf<E> {
         )?;
 
         // Map stack
-        let sp = self.create_and_init_stack(&mm_list, args, envs, aux_vec)?;
+        let sp = self
+            .create_and_init_stack(&mm_list, args, envs, aux_vec)
+            .await?;
 
         let entry_ip = if let Some(ldso_load_info) = ldso_load_info {
             // Normal shared object(DYN)
@@ -258,26 +260,30 @@ impl<E: ElfArch> Elf<E> {
         })
     }
 
-    fn create_and_init_stack(
+    async fn create_and_init_stack(
         &self,
         mm_list: &MMList,
         args: Vec<CString>,
         envs: Vec<CString>,
         aux_vec: AuxVec<E::Ea>,
     ) -> KResult<VAddr> {
-        mm_list.mmap_fixed(
-            VAddr::from(E::STACK_BASE_ADDR - INIT_STACK_SIZE),
-            INIT_STACK_SIZE,
-            Mapping::Anonymous,
-            Permission {
-                read: true,
-                write: true,
-                execute: false,
-            },
-            false,
-        )?;
+        mm_list
+            .mmap_fixed(
+                VAddr::from(E::STACK_BASE_ADDR - INIT_STACK_SIZE),
+                INIT_STACK_SIZE,
+                Mapping::Anonymous,
+                Permission {
+                    read: true,
+                    write: true,
+                    execute: false,
+                },
+                false,
+            )
+            .await?;
 
-        StackInitializer::new(&mm_list, E::STACK_BASE_ADDR, args, envs, aux_vec).init()
+        StackInitializer::new(&mm_list, E::STACK_BASE_ADDR, args, envs, aux_vec)
+            .init()
+            .await
     }
 
     fn init_aux_vec(&self, elf_base: VAddr, ldso_base: Option<VAddr>) -> KResult<AuxVec<E::Ea>> {
@@ -309,7 +315,7 @@ impl<E: ElfArch> Elf<E> {
         Ok(aux_vec)
     }
 
-    fn load_segments(&self, mm_list: &MMList) -> KResult<(VAddr, VAddr)> {
+    async fn load_segments(&self, mm_list: &MMList) -> KResult<(VAddr, VAddr)> {
         let base: VAddr = if self.is_shared_object() { E::DYN_BASE_ADDR } else { 0 }.into();
 
         let mut segments_end = VAddr::NULL;
@@ -318,7 +324,7 @@ impl<E: ElfArch> Elf<E> {
             let type_ = program_header.type_().map_err(|_| ENOEXEC)?;
 
             if type_ == program::Type::Load {
-                let segment_end = self.load_segment(program_header, mm_list, base)?;
+                let segment_end = self.load_segment(program_header, mm_list, base).await?;
 
                 if segment_end > segments_end {
                     segments_end = segment_end;
@@ -329,7 +335,7 @@ impl<E: ElfArch> Elf<E> {
         Ok((base, segments_end))
     }
 
-    fn load_segment(
+    async fn load_segment(
         &self,
         program_header: &E::Ph,
         mm_list: &MMList,
@@ -353,33 +359,37 @@ impl<E: ElfArch> Elf<E> {
         if file_len != 0 {
             let real_file_length = load_vaddr_end - vmap_start;
 
-            mm_list.mmap_fixed(
-                vmap_start,
-                file_len,
-                Mapping::File(FileMapping::new(
-                    self.file.get_inode()?,
-                    file_offset,
-                    real_file_length,
-                )),
-                permission,
-                false,
-            )?;
+            mm_list
+                .mmap_fixed(
+                    vmap_start,
+                    file_len,
+                    Mapping::File(FileMapping::new(
+                        self.file.get_inode()?,
+                        file_offset,
+                        real_file_length,
+                    )),
+                    permission,
+                    false,
+                )
+                .await?;
         }
 
         if vmem_len > file_len {
-            mm_list.mmap_fixed(
-                vmap_start + file_len,
-                vmem_len - file_len,
-                Mapping::Anonymous,
-                permission,
-                false,
-            )?;
+            mm_list
+                .mmap_fixed(
+                    vmap_start + file_len,
+                    vmem_len - file_len,
+                    Mapping::Anonymous,
+                    permission,
+                    false,
+                )
+                .await?;
         }
 
         Ok(vmap_start + vmem_len)
     }
 
-    fn load_ldso(&self, mm_list: &MMList) -> KResult<Option<LdsoLoadInfo>> {
+    async fn load_ldso(&self, mm_list: &MMList) -> KResult<Option<LdsoLoadInfo>> {
         let ldso_path = self.ldso_path()?;
 
         if let Some(ldso_path) = ldso_path {
@@ -393,7 +403,7 @@ impl<E: ElfArch> Elf<E> {
                 let type_ = program_header.type_().map_err(|_| ENOEXEC)?;
 
                 if type_ == program::Type::Load {
-                    ldso_elf.load_segment(program_header, mm_list, base)?;
+                    ldso_elf.load_segment(program_header, mm_list, base).await?;
                 }
             }
 
@@ -406,8 +416,8 @@ impl<E: ElfArch> Elf<E> {
         Ok(None)
     }
 
-    fn load_vdso(&self, mm_list: &MMList) -> KResult<()> {
-        mm_list.map_vdso()
+    async fn load_vdso(&self, mm_list: &MMList) -> KResult<()> {
+        mm_list.map_vdso().await
     }
 
     fn ldso_path(&self) -> KResult<Option<String>> {
@@ -449,10 +459,10 @@ impl ELF {
         }
     }
 
-    pub fn load(&self, args: Vec<CString>, envs: Vec<CString>) -> KResult<LoadInfo> {
+    pub async fn load(&self, args: Vec<CString>, envs: Vec<CString>) -> KResult<LoadInfo> {
         match &self {
-            ELF::Elf32(elf32) => elf32.load(args, envs),
-            ELF::Elf64(elf64) => elf64.load(args, envs),
+            ELF::Elf32(elf32) => elf32.load(args, envs).await,
+            ELF::Elf64(elf64) => elf64.load(args, envs).await,
         }
     }
 }
@@ -483,21 +493,21 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
     }
 
     // return sp after stack init
-    fn init(mut self) -> KResult<VAddr> {
-        let env_pointers = self.push_envs()?;
-        let arg_pointers = self.push_args()?;
+    async fn init(mut self) -> KResult<VAddr> {
+        let env_pointers = self.push_envs().await?;
+        let arg_pointers = self.push_args().await?;
 
         self.stack_alignment();
-        self.push_aux_vec()?;
-        self.push_pointers(env_pointers)?;
-        self.push_pointers(arg_pointers)?;
-        self.push_argc(T::from_usize(self.args.len()))?;
+        self.push_aux_vec().await?;
+        self.push_pointers(env_pointers).await?;
+        self.push_pointers(arg_pointers).await?;
+        self.push_argc(T::from_usize(self.args.len())).await?;
 
         assert_eq!(self.sp.align_down(16), self.sp);
         Ok(VAddr::from(self.sp))
     }
 
-    fn push_envs(&mut self) -> KResult<Vec<T>> {
+    async fn push_envs(&mut self) -> KResult<Vec<T>> {
         let mut addrs = Vec::with_capacity(self.envs.len());
         for string in self.envs.iter().rev() {
             let len = string.as_bytes_with_nul().len();
@@ -505,14 +515,15 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
             self.mm_list
                 .access_mut(VAddr::from(self.sp), len, |offset, data| {
                     data.copy_from_slice(&string.as_bytes_with_nul()[offset..offset + data.len()])
-                })?;
+                })
+                .await?;
             addrs.push(T::from_usize(self.sp));
         }
         addrs.reverse();
         Ok(addrs)
     }
 
-    fn push_args(&mut self) -> KResult<Vec<T>> {
+    async fn push_args(&mut self) -> KResult<Vec<T>> {
         let mut addrs = Vec::with_capacity(self.args.len());
         for string in self.args.iter().rev() {
             let len = string.as_bytes_with_nul().len();
@@ -520,7 +531,8 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
             self.mm_list
                 .access_mut(VAddr::from(self.sp), len, |offset, data| {
                     data.copy_from_slice(&string.as_bytes_with_nul()[offset..offset + data.len()])
-                })?;
+                })
+                .await?;
             addrs.push(T::from_usize(self.sp));
         }
         addrs.reverse();
@@ -538,27 +550,29 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
         self.sp = align_sp + all_size;
     }
 
-    fn push_pointers(&mut self, mut pointers: Vec<T>) -> KResult<()> {
+    async fn push_pointers(&mut self, mut pointers: Vec<T>) -> KResult<()> {
         pointers.push(T::from_usize(0));
         self.sp -= pointers.len() * size_of::<T>();
 
-        self.mm_list.access_mut(
-            VAddr::from(self.sp),
-            pointers.len() * size_of::<T>(),
-            |offset, data| {
-                data.copy_from_slice(unsafe {
-                    core::slice::from_raw_parts(
-                        pointers.as_ptr().byte_add(offset) as *const u8,
-                        data.len(),
-                    )
-                })
-            },
-        )?;
+        self.mm_list
+            .access_mut(
+                VAddr::from(self.sp),
+                pointers.len() * size_of::<T>(),
+                |offset, data| {
+                    data.copy_from_slice(unsafe {
+                        core::slice::from_raw_parts(
+                            pointers.as_ptr().byte_add(offset) as *const u8,
+                            data.len(),
+                        )
+                    })
+                },
+            )
+            .await?;
 
         Ok(())
     }
 
-    fn push_argc(&mut self, val: T) -> KResult<()> {
+    async fn push_argc(&mut self, val: T) -> KResult<()> {
         self.sp -= size_of::<T>();
 
         self.mm_list
@@ -566,12 +580,13 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
                 data.copy_from_slice(unsafe {
                     core::slice::from_raw_parts(&val as *const _ as *const u8, data.len())
                 })
-            })?;
+            })
+            .await?;
 
         Ok(())
     }
 
-    fn push_aux_vec(&mut self) -> KResult<()> {
+    async fn push_aux_vec(&mut self) -> KResult<()> {
         let mut longs: Vec<T> = vec![];
 
         // Write Auxiliary vectors
@@ -593,18 +608,20 @@ impl<'a, T: ElfAddr + Clone + Copy> StackInitializer<'a, T> {
 
         self.sp -= longs.len() * size_of::<T>();
 
-        self.mm_list.access_mut(
-            VAddr::from(self.sp),
-            longs.len() * size_of::<T>(),
-            |offset, data| {
-                data.copy_from_slice(unsafe {
-                    core::slice::from_raw_parts(
-                        longs.as_ptr().byte_add(offset) as *const u8,
-                        data.len(),
-                    )
-                })
-            },
-        )?;
+        self.mm_list
+            .access_mut(
+                VAddr::from(self.sp),
+                longs.len() * size_of::<T>(),
+                |offset, data| {
+                    data.copy_from_slice(unsafe {
+                        core::slice::from_raw_parts(
+                            longs.as_ptr().byte_add(offset) as *const u8,
+                            data.len(),
+                        )
+                    })
+                },
+            )
+            .await?;
 
         Ok(())
     }

+ 2 - 2
src/kernel/task/loader/mod.rs

@@ -106,9 +106,9 @@ impl ProgramLoader {
         })
     }
 
-    pub fn load(self) -> KResult<LoadInfo> {
+    pub async fn load(self) -> KResult<LoadInfo> {
         match self.object {
-            Object::ELF(elf) => elf.load(self.args, self.envs),
+            Object::ELF(elf) => elf.load(self.args, self.envs).await,
         }
     }
 }

+ 28 - 29
src/kernel/task/process.rs

@@ -1,4 +1,3 @@
-use super::block_on;
 use super::{
     process_group::ProcessGroupBuilder, signal::RaiseResult, thread::ThreadBuilder, ProcessGroup,
     ProcessList, Session, Thread,
@@ -109,6 +108,7 @@ pub struct DrainExited<'waitlist> {
     wait_procs: SpinGuard<'waitlist, VecDeque<WaitObject>>,
 }
 
+#[derive(Debug, Clone, Copy)]
 pub enum WaitId {
     Any,
     Pid(u32),
@@ -121,23 +121,17 @@ impl WaitId {
             P_ALL => Ok(WaitId::Any),
             P_PID => Ok(WaitId::Pid(id)),
             P_PGID => Ok(WaitId::Pgid(id)),
-            P_PIDFD => {
-                panic!("PDIFD type is unsupported")
-            }
+            P_PIDFD => panic!("P_PIDFD type is not supported"),
             _ => Err(EINVAL),
         }
     }
 
     pub fn from_id(id: i32, thread: &Thread) -> Self {
-        if id < -1 {
-            WaitId::Pgid((-id).cast_unsigned())
-        } else if id == -1 {
-            WaitId::Any
-        } else if id == 0 {
-            let procs = block_on(ProcessList::get().read());
-            WaitId::Pgid(thread.process.pgroup(procs.prove()).pgid)
-        } else {
-            WaitId::Pid(id.cast_unsigned())
+        match id {
+            ..-1 => WaitId::Pgid((-id).cast_unsigned()),
+            -1 => WaitId::Any,
+            0 => WaitId::Pgid(thread.process.pgroup_rcu().pgid),
+            _ => WaitId::Pid(id.cast_unsigned()),
         }
     }
 }
@@ -206,11 +200,11 @@ impl ProcessBuilder {
         }
     }
 
-    pub fn clone_from(mut self, process: Arc<Process>, clone_args: &CloneArgs) -> Self {
+    pub async fn clone_from(mut self, process: Arc<Process>, clone_args: &CloneArgs) -> Self {
         let mm_list = if clone_args.flags.contains(CloneFlags::CLONE_VM) {
-            block_on(process.mm_list.new_shared())
+            process.mm_list.new_shared().await
         } else {
-            block_on(process.mm_list.new_cloned())
+            process.mm_list.new_cloned().await
         };
 
         if let Some(exit_signal) = clone_args.exit_signal {
@@ -351,12 +345,18 @@ impl Process {
         trace_continue: bool,
     ) -> KResult<Option<WaitObject>> {
         let wait_object = {
-            let mut waits = self
-                .wait_list
-                .entry(wait_id, trace_stop, trace_continue)
-                .await;
+            let mut unlocked_waits = None;
 
             loop {
+                let mut waits = match unlocked_waits {
+                    Some(wait) => wait.await?,
+                    None => {
+                        self.wait_list
+                            .entry(wait_id, trace_stop, trace_continue)
+                            .await
+                    }
+                };
+
                 if let Some(object) = waits.get() {
                     break object;
                 }
@@ -374,7 +374,7 @@ impl Process {
                     return Ok(None);
                 }
 
-                waits = waits.wait(no_block).await?;
+                unlocked_waits = Some(waits.wait(no_block));
             }
         };
 
@@ -395,8 +395,8 @@ impl Process {
     }
 
     /// Create a new session for the process.
-    pub fn setsid(self: &Arc<Self>) -> KResult<u32> {
-        let mut process_list = block_on(ProcessList::get().write());
+    pub async fn setsid(self: &Arc<Self>) -> KResult<u32> {
+        let mut process_list = ProcessList::get().write().await;
         // If there exists a session that has the same sid as our pid, we can't create a new
         // session. The standard says that we should create a new process group and be the
         // only process in the new process group and session.
@@ -473,8 +473,8 @@ impl Process {
     ///
     /// This function should be called on the process that issued the syscall in order to do
     /// permission checks.
-    pub fn setpgid(self: &Arc<Self>, pid: u32, pgid: u32) -> KResult<()> {
-        let mut procs = block_on(ProcessList::get().write());
+    pub async fn setpgid(self: &Arc<Self>, pid: u32, pgid: u32) -> KResult<()> {
+        let mut procs = ProcessList::get().write().await;
         // We may set pgid of either the calling process or a child process.
         if pid == self.pid {
             self.do_setpgid(pgid, &mut procs)
@@ -609,9 +609,8 @@ impl Entry<'_, '_, '_> {
                 WaitId::Any => true,
                 WaitId::Pid(pid) => item.pid == pid,
                 WaitId::Pgid(pgid) => {
-                    let procs = block_on(ProcessList::get().read());
-                    if let Some(process) = procs.try_find_process(item.pid) {
-                        return process.pgroup(procs.prove()).pgid == pgid;
+                    if let Some(process) = self.process_list.try_find_process(item.pid) {
+                        return process.pgroup(self.process_list.prove()).pgid == pgid;
                     }
                     false
                 }
@@ -625,7 +624,7 @@ impl Entry<'_, '_, '_> {
         }
     }
 
-    pub fn wait(self, no_block: bool) -> impl core::future::Future<Output = KResult<Self>> {
+    pub fn wait(self, no_block: bool) -> impl core::future::Future<Output = KResult<Self>> + Send {
         let wait_procs = self.wait_procs.unlock();
 
         async move {

+ 3 - 4
src/kernel/task/process_list.rs

@@ -9,6 +9,7 @@ use alloc::{
     collections::btree_map::BTreeMap,
     sync::{Arc, Weak},
 };
+use eonix_mm::address::Addr;
 use eonix_sync::{AsProof as _, AsProofMut as _, RwLock};
 
 pub struct ProcessList {
@@ -134,11 +135,9 @@ impl ProcessList {
         }
 
         if let Some(clear_ctid) = thread.get_clear_ctid() {
-            let _ = UserPointerMut::new(clear_ctid as *mut u32)
-                .unwrap()
-                .write(0u32);
+            let _ = UserPointerMut::new(clear_ctid).unwrap().write(0u32);
 
-            let _ = futex_wake(clear_ctid, None, 1).await;
+            let _ = futex_wake(clear_ctid.addr(), None, 1).await;
         }
 
         if let Some(robust_list) = thread.get_robust_list() {

+ 3 - 3
src/kernel/task/signal.rs

@@ -293,15 +293,15 @@ impl SignalList {
         let old_fpu_state_vaddr = old_trap_ctx_vaddr + size_of::<TrapContext>();
         let old_mask_vaddr = old_fpu_state_vaddr + size_of::<FpuState>();
 
-        *trap_ctx = UserPointer::<TrapContext>::new_vaddr(old_trap_ctx_vaddr)?.read()?;
+        *trap_ctx = UserPointer::<TrapContext>::with_addr(old_trap_ctx_vaddr)?.read()?;
 
         // Make sure that at least we won't crash the kernel.
         if !trap_ctx.is_user_mode() || !trap_ctx.is_interrupt_enabled() {
             return Err(EFAULT)?;
         }
 
-        *fpu_state = UserPointer::<FpuState>::new_vaddr(old_fpu_state_vaddr)?.read()?;
-        self.inner.lock().mask = UserPointer::<SigSet>::new_vaddr(old_mask_vaddr)?.read()?;
+        *fpu_state = UserPointer::<FpuState>::with_addr(old_fpu_state_vaddr)?.read()?;
+        self.inner.lock().mask = UserPointer::<SigSet>::with_addr(old_mask_vaddr)?.read()?;
 
         Ok(())
     }

+ 3 - 2
src/kernel/task/signal/signal_action.rs

@@ -3,6 +3,7 @@ use crate::{
     io::BufferFill as _,
     kernel::{
         constants::{EFAULT, EINVAL},
+        syscall::UserMut,
         user::UserBuffer,
     },
 };
@@ -152,7 +153,7 @@ impl SignalAction {
         let saved_data_addr = (current_sp - SAVED_DATA_SIZE).floor_to(16);
 
         let mut saved_data_buffer =
-            UserBuffer::new(saved_data_addr.addr() as *mut u8, SAVED_DATA_SIZE)?;
+            UserBuffer::new(UserMut::new(saved_data_addr), SAVED_DATA_SIZE)?;
 
         saved_data_buffer.copy(trap_ctx)?.ok_or(EFAULT)?;
         saved_data_buffer.copy(fpu_state)?.ok_or(EFAULT)?;
@@ -200,7 +201,7 @@ impl SignalAction {
             Some(return_address),
             &[Long::new_val(signal.into_raw() as _).get()],
             |vaddr, data| -> Result<(), u32> {
-                let mut buffer = UserBuffer::new(vaddr.addr() as *mut u8, data.len())?;
+                let mut buffer = UserBuffer::new(UserMut::new(vaddr), data.len())?;
                 for ch in data.iter() {
                     buffer.copy(&ch)?.ok_or(EFAULT)?;
                 }

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

@@ -5,7 +5,7 @@ use super::{
 use crate::{
     kernel::{
         interrupt::default_irq_handler,
-        syscall::{syscall_handlers, SyscallHandler},
+        syscall::{syscall_handlers, SyscallHandler, User, UserMut},
         task::{clone::CloneArgs, futex::RobustListHead, CloneFlags},
         timer::{should_reschedule, timer_interrupt},
         user::{UserPointer, UserPointerMut},
@@ -13,7 +13,7 @@ use crate::{
     },
     prelude::*,
 };
-use alloc::sync::Arc;
+use alloc::{alloc::Allocator, sync::Arc};
 use atomic_unique_refcell::AtomicUniqueRefCell;
 use core::{
     future::{poll_fn, Future},
@@ -36,10 +36,14 @@ use eonix_mm::address::{Addr as _, VAddr};
 use eonix_sync::AsProofMut as _;
 use pointers::BorrowedArc;
 use posix_types::signal::Signal;
+use stalloc::UnsafeStalloc;
 
 #[eonix_percpu::define_percpu]
 static CURRENT_THREAD: Option<NonNull<Thread>> = None;
 
+#[derive(Clone, Copy)]
+pub struct ThreadAlloc<'a>(pub &'a UnsafeStalloc<255, 32>);
+
 pub struct ThreadBuilder {
     tid: Option<u32>,
     name: Option<Arc<[u8]>>,
@@ -48,8 +52,8 @@ pub struct ThreadBuilder {
     fs_context: Option<Arc<FsContext>>,
     signal_list: Option<SignalList>,
     tls: Option<UserTLS>,
-    set_child_tid: Option<usize>,
-    clear_child_tid: Option<usize>,
+    set_child_tid: Option<UserMut<u32>>,
+    clear_child_tid: Option<UserMut<u32>>,
 
     trap_ctx: Option<TrapContext>,
     fpu_state: Option<FpuState>,
@@ -65,11 +69,11 @@ struct ThreadInner {
 
     /// User pointer
     /// Store child thread's tid when child thread returns to user space.
-    set_child_tid: Option<usize>,
+    set_child_tid: Option<UserMut<u32>>,
 
-    clear_child_tid: Option<usize>,
+    clear_child_tid: Option<UserMut<u32>>,
 
-    robust_list_address: Option<VAddr>,
+    robust_list_address: Option<User<RobustListHead>>,
 }
 
 pub struct Thread {
@@ -141,12 +145,12 @@ impl ThreadBuilder {
         self
     }
 
-    pub fn set_child_tid(mut self, set_child_tid: Option<usize>) -> Self {
+    pub fn set_child_tid(mut self, set_child_tid: Option<UserMut<u32>>) -> Self {
         self.set_child_tid = set_child_tid;
         self
     }
 
-    pub fn clear_child_tid(mut self, clear_child_tid: Option<usize>) -> Self {
+    pub fn clear_child_tid(mut self, clear_child_tid: Option<UserMut<u32>>) -> Self {
         self.clear_child_tid = clear_child_tid;
         self
     }
@@ -285,13 +289,13 @@ impl Thread {
         Ok(())
     }
 
-    pub fn set_robust_list(&self, robust_list_address: Option<VAddr>) {
+    pub fn set_robust_list(&self, robust_list_address: Option<User<RobustListHead>>) {
         self.inner.lock().robust_list_address = robust_list_address;
     }
 
     pub fn get_robust_list(&self) -> Option<RobustListHead> {
         let addr = self.inner.lock().robust_list_address?;
-        let user_pointer = UserPointer::new(addr.addr() as *const RobustListHead).ok()?;
+        let user_pointer = UserPointer::new(addr).ok()?;
 
         user_pointer.read().ok()
     }
@@ -304,25 +308,30 @@ impl Thread {
         self.inner.lock().name.clone()
     }
 
-    pub fn clear_child_tid(&self, clear_child_tid: Option<usize>) {
+    pub fn clear_child_tid(&self, clear_child_tid: Option<UserMut<u32>>) {
         self.inner.lock().clear_child_tid = clear_child_tid;
     }
 
-    pub fn get_set_ctid(&self) -> Option<usize> {
+    pub fn get_set_ctid(&self) -> Option<UserMut<u32>> {
         self.inner.lock().set_child_tid
     }
 
-    pub fn get_clear_ctid(&self) -> Option<usize> {
+    pub fn get_clear_ctid(&self) -> Option<UserMut<u32>> {
         self.inner.lock().clear_child_tid
     }
 
-    pub fn handle_syscall(&self, no: usize, args: [usize; 6]) -> Option<usize> {
+    pub async fn handle_syscall(
+        &self,
+        thd_alloc: ThreadAlloc<'_>,
+        no: usize,
+        args: [usize; 6],
+    ) -> Option<usize> {
         match syscall_handlers().get(no) {
             Some(Some(SyscallHandler {
                 handler,
                 name: _name,
                 ..
-            })) => handler(self, args),
+            })) => handler(self, thd_alloc, args).await,
             _ => {
                 println_warn!("Syscall {no}({no:#x}) isn't implemented.");
                 self.raise(Signal::SIGSYS);
@@ -347,12 +356,18 @@ impl Thread {
 
     async fn real_run(&self) {
         if let Some(set_ctid) = self.get_set_ctid() {
-            UserPointerMut::new(set_ctid as *mut u32)
+            UserPointerMut::new(set_ctid)
                 .expect("set_child_tid pointer is invalid")
                 .write(self.tid)
                 .expect("set_child_tid write failed");
         }
 
+        let stack_alloc = unsafe {
+            // SAFETY: The allocator will only be used within the context of this thread.
+            UnsafeStalloc::new()
+        };
+        let thd_alloc = ThreadAlloc(&stack_alloc);
+
         while !self.is_dead() {
             if self.signal_list.has_pending_signal() {
                 self.signal_list
@@ -401,7 +416,7 @@ impl Thread {
                     }
                 }
                 TrapType::Syscall { no, args } => {
-                    if let Some(retval) = self.handle_syscall(no, args) {
+                    if let Some(retval) = self.handle_syscall(thd_alloc, no, args).await {
                         let mut trap_ctx = self.trap_ctx.borrow();
                         trap_ctx.set_user_return_value(retval);
 
@@ -452,6 +467,19 @@ impl Thread {
     }
 }
 
+unsafe impl Allocator for ThreadAlloc<'_> {
+    fn allocate(
+        &self,
+        layout: core::alloc::Layout,
+    ) -> Result<NonNull<[u8]>, alloc::alloc::AllocError> {
+        self.0.allocate(layout)
+    }
+
+    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: core::alloc::Layout) {
+        self.0.deallocate(ptr, layout);
+    }
+}
+
 pub async fn yield_now() {
     struct Yield {
         yielded: bool,

+ 8 - 8
src/kernel/terminal.rs

@@ -1,5 +1,5 @@
 use super::{
-    task::{block_on, ProcessList, Session, Thread},
+    task::{ProcessList, Session, Thread},
     user::{UserPointer, UserPointerMut},
 };
 use crate::kernel::constants::{EINTR, ENOTTY, EPERM};
@@ -446,18 +446,18 @@ impl Terminal {
         }
     }
 
-    fn signal(&self, inner: &mut TerminalInner, signal: Signal) {
+    async fn signal(&self, inner: &mut TerminalInner, signal: Signal) {
         if let Some(session) = inner.session.upgrade() {
-            block_on(session.raise_foreground(signal));
+            session.raise_foreground(signal).await;
         }
         if !inner.termio.noflsh() {
             self.clear_read_buffer(inner);
         }
     }
 
-    fn echo_and_signal(&self, inner: &mut TerminalInner, ch: u8, signal: Signal) {
+    async fn echo_and_signal(&self, inner: &mut TerminalInner, ch: u8, signal: Signal) {
         self.echo_char(inner, ch);
-        self.signal(inner, signal);
+        self.signal(inner, signal).await;
     }
 
     fn do_commit_char(&self, inner: &mut TerminalInner, ch: u8) {
@@ -481,13 +481,13 @@ impl Terminal {
             match ch {
                 0xff => {}
                 ch if ch == inner.termio.vintr() => {
-                    return self.echo_and_signal(&mut inner, ch, Signal::SIGINT)
+                    return self.echo_and_signal(&mut inner, ch, Signal::SIGINT).await
                 }
                 ch if ch == inner.termio.vquit() => {
-                    return self.echo_and_signal(&mut inner, ch, Signal::SIGQUIT)
+                    return self.echo_and_signal(&mut inner, ch, Signal::SIGQUIT).await
                 }
                 ch if ch == inner.termio.vsusp() => {
-                    return self.echo_and_signal(&mut inner, ch, Signal::SIGTSTP)
+                    return self.echo_and_signal(&mut inner, ch, Signal::SIGTSTP).await
                 }
                 _ => {}
             }

+ 2 - 6
src/kernel/user.rs

@@ -1,7 +1,3 @@
-pub mod dataflow;
+mod dataflow;
 
-#[allow(unused_imports)]
-pub use dataflow::{UserBuffer, UserString};
-
-pub type UserPointer<'a, T> = dataflow::UserPointer<'a, T, true>;
-pub type UserPointerMut<'a, T> = dataflow::UserPointer<'a, T, false>;
+pub use dataflow::{CheckedUserPointer, UserBuffer, UserPointer, UserPointerMut, UserString};

+ 70 - 45
src/kernel/user/dataflow.rs

@@ -1,17 +1,20 @@
+use crate::{
+    io::{Buffer, FillResult},
+    prelude::*,
+};
 use crate::{
     io::{IntoStream, Stream},
-    kernel::constants::{EFAULT, EINVAL},
+    kernel::{
+        constants::{EFAULT, EINVAL},
+        syscall::{User, UserMut},
+    },
 };
 use core::{arch::asm, ffi::CStr, marker::PhantomData};
+use eonix_mm::address::Addr;
 use eonix_preempt::assert_preempt_enabled;
 
-use crate::{
-    io::{Buffer, FillResult},
-    prelude::*,
-};
-
 pub struct CheckedUserPointer<'a> {
-    ptr: *const u8,
+    ptr: User<u8>,
     len: usize,
     _phantom: PhantomData<&'a ()>,
 }
@@ -27,7 +30,12 @@ pub struct UserString<'a> {
     len: usize,
 }
 
-pub struct UserPointer<'a, T: Copy, const CONST: bool> {
+pub struct UserPointer<'a, T: Copy> {
+    pointer: CheckedUserPointer<'a>,
+    _phantom: PhantomData<T>,
+}
+
+pub struct UserPointerMut<'a, T: Copy> {
     pointer: CheckedUserPointer<'a>,
     _phantom: PhantomData<T>,
 }
@@ -37,9 +45,9 @@ pub struct UserStream<'a> {
     cur: usize,
 }
 
-impl<T: Copy, const CONST: bool> UserPointer<'_, T, CONST> {
-    pub fn new(ptr: *const T) -> KResult<Self> {
-        let pointer = CheckedUserPointer::new(ptr as *const u8, core::mem::size_of::<T>())?;
+impl<T: Copy> UserPointer<'_, T> {
+    pub fn new(ptr: User<T>) -> KResult<Self> {
+        let pointer = CheckedUserPointer::new(ptr.cast(), core::mem::size_of::<T>())?;
 
         Ok(Self {
             pointer,
@@ -47,8 +55,8 @@ impl<T: Copy, const CONST: bool> UserPointer<'_, T, CONST> {
         })
     }
 
-    pub fn new_vaddr(vaddr: usize) -> KResult<Self> {
-        Self::new(vaddr as *mut T)
+    pub fn with_addr(vaddr: usize) -> KResult<Self> {
+        Self::new(User::with_addr(vaddr))
     }
 
     /// # Might Sleep
@@ -60,22 +68,48 @@ impl<T: Copy, const CONST: bool> UserPointer<'_, T, CONST> {
     }
 
     pub fn offset(&self, offset: isize) -> KResult<Self> {
-        let new_vaddr = self.pointer.ptr as isize + offset * size_of::<T>() as isize;
-        Self::new_vaddr(new_vaddr as usize)
+        let new_ptr = self.pointer.ptr.offset(offset * size_of::<T>() as isize);
+        Self::new(new_ptr.cast())
     }
 }
 
-impl<'a, T: Copy> UserPointer<'a, T, false> {
+impl<'a, T: Copy> UserPointerMut<'a, T> {
+    pub fn new(ptr: UserMut<T>) -> KResult<Self> {
+        let pointer = CheckedUserPointer::new(ptr.cast().as_const(), core::mem::size_of::<T>())?;
+
+        Ok(Self {
+            pointer,
+            _phantom: PhantomData,
+        })
+    }
+
+    pub fn with_addr(vaddr: usize) -> KResult<Self> {
+        Self::new(UserMut::with_addr(vaddr))
+    }
+
+    /// # Might Sleep
+    pub fn read(&self) -> KResult<T> {
+        let mut value = core::mem::MaybeUninit::<T>::uninit();
+        self.pointer
+            .read(value.as_mut_ptr() as *mut (), core::mem::size_of::<T>())?;
+        Ok(unsafe { value.assume_init() })
+    }
+
+    pub fn offset(&self, offset: isize) -> KResult<Self> {
+        let new_ptr = self.pointer.ptr.offset(offset * size_of::<T>() as isize);
+        Self::new(unsafe { new_ptr.cast().as_mut() })
+    }
+
     pub fn write(&self, value: T) -> KResult<()> {
         self.pointer
-            .write(&value as *const T as *mut (), core::mem::size_of::<T>())
+            .write(&raw const value as *mut (), core::mem::size_of::<T>())
     }
 }
 
 impl CheckedUserPointer<'_> {
-    pub fn new(ptr: *const u8, len: usize) -> KResult<Self> {
+    pub fn new(ptr: User<u8>, len: usize) -> KResult<Self> {
         const USER_MAX_ADDR: usize = 0x7ff_fff_fff_fff;
-        let end = (ptr as usize).checked_add(len);
+        let end = ptr.addr().checked_add(len);
         if ptr.is_null() || end.ok_or(EFAULT)? > USER_MAX_ADDR {
             Err(EFAULT)
         } else {
@@ -89,19 +123,10 @@ impl CheckedUserPointer<'_> {
 
     pub fn forward(&mut self, offset: usize) {
         assert!(offset <= self.len);
-        self.ptr = self.ptr.wrapping_offset(offset as isize);
+        self.ptr = self.ptr.offset(offset as isize);
         self.len -= offset;
     }
 
-    pub fn get_const<T>(&self) -> *const T {
-        self.ptr as *const T
-    }
-
-    pub fn as_slice(&self) -> &[u8] {
-        // SAFETY: the pointer's validity is checked in `new`
-        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
-    }
-
     /// # Might Sleep
     pub fn read(&self, buffer: *mut (), total: usize) -> KResult<()> {
         assert_preempt_enabled!("UserPointer::read");
@@ -126,7 +151,7 @@ impl CheckedUserPointer<'_> {
                 ".quad 0x3",     // type: load
                 ".popsection",
                 inout("rcx") total => error_bytes,
-                inout("rsi") self.ptr => _,
+                inout("rsi") self.ptr.addr() => _,
                 inout("rdi") buffer => _,
             );
 
@@ -148,7 +173,7 @@ impl CheckedUserPointer<'_> {
                 ".8byte 0x3",     // type: load
                 ".popsection",
                 inout("a0") total => error_bytes,
-                inout("a1") self.ptr => _,
+                inout("a1") self.ptr.addr() => _,
                 inout("a2") buffer => _,
                 out("t0") _,
             );
@@ -171,7 +196,7 @@ impl CheckedUserPointer<'_> {
                 ".8byte 0x3",     // type: load
                 ".popsection",
                 inout("$a0") total => error_bytes,
-                inout("$a1") self.ptr => _,
+                inout("$a1") self.ptr.addr() => _,
                 inout("$a2") buffer => _,
                 out("$t0") _,
             );
@@ -210,7 +235,7 @@ impl CheckedUserPointer<'_> {
                 ".popsection",
                 inout("rcx") total => error_bytes,
                 inout("rsi") data => _,
-                inout("rdi") self.ptr => _,
+                inout("rdi") self.ptr.addr() => _,
             );
 
             #[cfg(target_arch = "riscv64")]
@@ -232,7 +257,7 @@ impl CheckedUserPointer<'_> {
                 ".popsection",
                 inout("a0") total => error_bytes,
                 inout("a1") data => _,
-                inout("a2") self.ptr => _,
+                inout("a2") self.ptr.addr() => _,
                 out("t0") _,
             );
 
@@ -255,7 +280,7 @@ impl CheckedUserPointer<'_> {
                 ".popsection",
                 inout("$a0") total => error_bytes,
                 inout("$a1") data => _,
-                inout("$a2") self.ptr => _,
+                inout("$a2") self.ptr.addr() => _,
                 out("$t0") _,
             );
         };
@@ -293,7 +318,7 @@ impl CheckedUserPointer<'_> {
                 ".popsection",
                 in("rax") 0,
                 inout("rcx") self.len => error_bytes,
-                inout("rdi") self.ptr => _,
+                inout("rdi") self.ptr.addr() => _,
                 options(att_syntax)
             );
 
@@ -313,7 +338,7 @@ impl CheckedUserPointer<'_> {
                 ".8byte 0x1", // type: store
                 ".popsection",
                 inout("a0") self.len => error_bytes,
-                inout("a1") self.ptr => _,
+                inout("a1") self.ptr.addr() => _,
             );
 
             #[cfg(target_arch = "loongarch64")]
@@ -332,7 +357,7 @@ impl CheckedUserPointer<'_> {
                 ".8byte 0x1", // type: store
                 ".popsection",
                 inout("$a0") self.len => error_bytes,
-                inout("$a1") self.ptr => _,
+                inout("$a1") self.ptr.addr() => _,
             );
         };
 
@@ -345,8 +370,8 @@ impl CheckedUserPointer<'_> {
 }
 
 impl UserBuffer<'_> {
-    pub fn new(ptr: *mut u8, size: usize) -> KResult<Self> {
-        let ptr = CheckedUserPointer::new(ptr, size)?;
+    pub fn new(ptr: UserMut<u8>, size: usize) -> KResult<Self> {
+        let ptr = CheckedUserPointer::new(ptr.as_const(), size)?;
 
         Ok(Self { ptr, size, cur: 0 })
     }
@@ -388,7 +413,7 @@ impl<'lt> Buffer for UserBuffer<'lt> {
 
 impl<'lt> UserString<'lt> {
     /// # Might Sleep
-    pub fn new(ptr: *const u8) -> KResult<Self> {
+    pub fn new(ptr: User<u8>) -> KResult<Self> {
         assert_preempt_enabled!("UserString::new");
 
         const MAX_LEN: usize = 4096;
@@ -416,7 +441,7 @@ impl<'lt> UserString<'lt> {
                 ".popsection",
                 out("al") _,
                 inout("rcx") MAX_LEN => result,
-                ptr = inout(reg) ptr.ptr => _,
+                ptr = inout(reg) ptr.ptr.addr() => _,
                 options(att_syntax),
             );
 
@@ -439,7 +464,7 @@ impl<'lt> UserString<'lt> {
                 ".popsection",
                 out("t0") _,
                 inout("a0") MAX_LEN => result,
-                inout("a1") ptr.ptr => _,
+                inout("a1") ptr.ptr.addr() => _,
             );
 
             #[cfg(target_arch = "loongarch64")]
@@ -461,7 +486,7 @@ impl<'lt> UserString<'lt> {
                 ".popsection",
                 out("$t0") _,
                 inout("$a0") MAX_LEN => result,
-                inout("$a1") ptr.ptr => _,
+                inout("$a1") ptr.ptr.addr() => _,
             );
         };
 
@@ -478,7 +503,7 @@ impl<'lt> UserString<'lt> {
     pub fn as_cstr(&self) -> &'lt CStr {
         unsafe {
             CStr::from_bytes_with_nul_unchecked(core::slice::from_raw_parts(
-                self.ptr.get_const(),
+                self.ptr.ptr.addr() as *const u8,
                 self.len + 1,
             ))
         }

+ 5 - 5
src/kernel/vfs/file.rs

@@ -466,11 +466,11 @@ impl TerminalFile {
 
     fn ioctl(&self, request: usize, arg3: usize) -> KResult<()> {
         block_on(self.terminal.ioctl(match request as u32 {
-            TCGETS => TerminalIORequest::GetTermios(UserPointerMut::new_vaddr(arg3)?),
-            TCSETS => TerminalIORequest::SetTermios(UserPointer::new_vaddr(arg3)?),
-            TIOCGPGRP => TerminalIORequest::GetProcessGroup(UserPointerMut::new_vaddr(arg3)?),
-            TIOCSPGRP => TerminalIORequest::SetProcessGroup(UserPointer::new_vaddr(arg3)?),
-            TIOCGWINSZ => TerminalIORequest::GetWindowSize(UserPointerMut::new_vaddr(arg3)?),
+            TCGETS => TerminalIORequest::GetTermios(UserPointerMut::with_addr(arg3)?),
+            TCSETS => TerminalIORequest::SetTermios(UserPointer::with_addr(arg3)?),
+            TIOCGPGRP => TerminalIORequest::GetProcessGroup(UserPointerMut::with_addr(arg3)?),
+            TIOCSPGRP => TerminalIORequest::SetProcessGroup(UserPointer::with_addr(arg3)?),
+            TIOCGWINSZ => TerminalIORequest::GetWindowSize(UserPointerMut::with_addr(arg3)?),
             _ => return Err(EINVAL),
         }))
     }

+ 2 - 0
src/lib.rs

@@ -1,5 +1,6 @@
 #![no_std]
 #![no_main]
+#![feature(allocator_api)]
 #![feature(c_size_t)]
 #![feature(concat_idents)]
 #![feature(arbitrary_self_types)]
@@ -253,6 +254,7 @@ async fn init_process(early_kstack: PRange) {
         ProgramLoader::parse(fs_context, init_name, init.clone(), argv, envp)
             .expect("Failed to parse init program")
             .load()
+            .await
             .expect("Failed to load init program")
     };