Prechádzať zdrojové kódy

feat: bug fix and some temporary solutions

(cherry picked from commit f9ef0a532129218ef1254a2a20617a26f159e820)
Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf 6 mesiacov pred
rodič
commit
fdc65f0d30

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

@@ -10,7 +10,7 @@ bitflags! {
         const GLOBAL = 8;
     }
 
-    #[derive(Clone, Copy, PartialEq)]
+    #[derive(Debug, Clone, Copy, PartialEq)]
     pub struct PageAttribute: usize {
         const PRESENT = 1;
         const READ = 2;

+ 4 - 3
crates/eonix_runtime/src/scheduler.rs

@@ -9,7 +9,7 @@ use alloc::sync::Arc;
 use core::{
     mem::forget,
     ptr::NonNull,
-    sync::atomic::{compiler_fence, Ordering},
+    sync::atomic::{compiler_fence, AtomicUsize, Ordering},
     task::Waker,
 };
 use eonix_hal::processor::halt;
@@ -136,8 +136,9 @@ impl Scheduler {
         unsafe { TASKS.lock().cursor_mut_from_ptr(task as *const _).remove() };
     }
 
-    fn select_cpu_for_task(&self, task: &Task) -> usize {
-        task.cpu.load(Ordering::Relaxed) as _
+    fn select_cpu_for_task(&self, _task: &Task) -> usize {
+        static NEXT_CPU: AtomicUsize = AtomicUsize::new(0);
+        NEXT_CPU.fetch_add(1, Ordering::Relaxed) % 4
     }
 
     pub fn activate(&self, task: &Arc<Task>) {

+ 1 - 0
crates/posix_types/src/lib.rs

@@ -4,6 +4,7 @@ pub mod constants;
 pub mod ctypes;
 pub mod namei;
 pub mod open;
+pub mod poll;
 pub mod result;
 pub mod signal;
 pub mod stat;

+ 5 - 0
crates/posix_types/src/poll.rs

@@ -0,0 +1,5 @@
+pub const FDSET_LENGTH: usize = 1024 / (8 * size_of::<usize>());
+
+pub struct FDSet {
+    fds_bits: [usize; FDSET_LENGTH],
+}

+ 8 - 0
crates/posix_types/src/stat.rs

@@ -1,3 +1,5 @@
+use core::time::Duration;
+
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct StatXTimestamp {
@@ -100,3 +102,9 @@ impl From<StatX> for Stat {
         }
     }
 }
+
+impl From<TimeSpec> for Duration {
+    fn from(value: TimeSpec) -> Self {
+        Self::new(value.tv_sec, value.tv_nsec)
+    }
+}

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

@@ -71,7 +71,7 @@ pub const SYS_PWRITE64: usize = 68;
 pub const SYS_PREADV: usize = 69;
 pub const SYS_PWRITEV: usize = 70;
 pub const SYS_SENDFILE64: usize = 71;
-pub const SYS_PSELECT6_TIME32: usize = 72;
+pub const SYS_PSELECT6: usize = 72;
 pub const SYS_PPOLL: usize = 73;
 pub const SYS_SIGNALFD4: usize = 74;
 pub const SYS_VMSPLICE: usize = 75;
@@ -114,7 +114,7 @@ pub const SYS_TIMER_DELETE: usize = 111;
 pub const SYS_CLOCK_SETTIME: usize = 404;
 pub const SYS_CLOCK_GETTIME: usize = 113;
 pub const SYS_CLOCK_GETRES: usize = 406;
-pub const SYS_CLOCK_NANOSLEEP: usize = 407;
+pub const SYS_CLOCK_NANOSLEEP: usize = 115;
 pub const SYS_SYSLOG: usize = 116;
 pub const SYS_PTRACE: usize = 117;
 pub const SYS_SCHED_SETPARAM: usize = 118;

+ 55 - 6
src/fs/shm.rs

@@ -6,7 +6,7 @@ use eonix_sync::{LazyLock, Mutex};
 
 use crate::{
     fs::tmpfs::{DirectoryInode, FileInode, TmpFs},
-    kernel::{constants::ENOSPC, vfs::inode::Mode},
+    kernel::{constants::ENOSPC, timer::Instant, vfs::inode::Mode},
     prelude::KResult,
 };
 
@@ -40,9 +40,58 @@ pub struct ShmManager {
     areas: BTreeMap<u32, ShmArea>,
 }
 
+#[repr(C)]
+#[derive(Default, Clone, Copy, Debug)]
+pub struct IpcPerm {
+    key: i32,
+    uid: u32,
+    gid: u32,
+    cuid: u32,
+    cgid: u32,
+    mode: u16,
+    seq: u16,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct ShmIdDs {
+    // Ownership and permissions
+    pub shm_perm: IpcPerm,
+    // Size of segment (bytes). In our system, this must be aligned
+    pub shm_segsz: usize,
+    // Last attach time
+    pub shm_atime: usize,
+    // Last detach time
+    pub shm_dtime: usize,
+    // Creation time/time of last modification via shmctl()
+    pub shm_ctime: usize,
+    // PID of creator
+    pub shm_cpid: usize,
+    // PID of last shmat(2)/shmdt(2)
+    pub shm_lpid: usize,
+    // No. of current attaches
+    pub shm_nattch: usize,
+}
+
+impl ShmIdDs {
+    fn new(size: usize, pid: u32) -> Self {
+        Self {
+            shm_perm: IpcPerm::default(),
+            shm_segsz: size,
+            shm_atime: 0,
+            shm_dtime: 0,
+            shm_ctime: 0, // Should set instant now
+            shm_cpid: pid as usize,
+            shm_lpid: 0,
+            shm_nattch: 0,
+        }
+    }
+}
+
+#[derive(Debug)]
 pub struct ShmArea {
     pub area: Arc<FileInode>,
-    pub size: usize,
+    pub shmid_ds: ShmIdDs,
 }
 
 // A big lock here to protect the shared memory area.
@@ -60,12 +109,12 @@ impl ShmManager {
         }
     }
 
-    pub fn create_shared_area(&self, size: usize, mode: Mode) -> ShmArea {
+    pub fn create_shared_area(&self, size: usize, pid: u32, mode: Mode) -> ShmArea {
         let ino = self.tmpfs.assign_ino();
         let vfs = Arc::downgrade(&self.tmpfs);
         ShmArea {
-            area: FileInode::new(ino, vfs, mode),
-            size,
+            area: FileInode::new(ino, vfs, size, mode),
+            shmid_ds: ShmIdDs::new(size, pid),
         }
     }
 
@@ -86,7 +135,7 @@ pub fn gen_shm_id(key: usize) -> KResult<u32> {
     if key == IPC_PRIVATE {
         let shmid = NEXT_SHMID.fetch_add(1, Ordering::Relaxed);
 
-        if shmid < SHM_MAGIC {
+        if shmid >= SHM_MAGIC {
             return Err(ENOSPC);
         } else {
             return Ok(shmid);

+ 24 - 13
src/fs/tmpfs.rs

@@ -18,6 +18,7 @@ use crate::{
     prelude::*,
 };
 use alloc::sync::{Arc, Weak};
+use core::fmt::Debug;
 use core::{ops::ControlFlow, sync::atomic::Ordering};
 use eonix_mm::paging::PAGE_SIZE;
 use eonix_runtime::task::Task;
@@ -155,7 +156,7 @@ impl Inode for DirectoryInode {
         let rwsem = Task::block_on(self.rwsem.write());
 
         let ino = vfs.assign_ino();
-        let file = FileInode::new(ino, self.vfs.clone(), mode);
+        let file = FileInode::new(ino, self.vfs.clone(), 0, mode);
 
         self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
         at.save_reg(file)
@@ -468,19 +469,25 @@ define_struct_inode! {
     }
 }
 
+impl Debug for FileInode {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "FileInode({:?})", self.idata)
+    }
+}
+
 impl FileInode {
-    pub fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
-        Arc::new_cyclic(|weak_self: &Weak<FileInode>| FileInode {
-            idata: {
-                let inode_data = InodeData::new(ino, vfs);
-                inode_data
-                    .mode
-                    .store(S_IFREG | (mode & 0o777), Ordering::Relaxed);
-                inode_data.nlink.store(1, Ordering::Relaxed);
-                inode_data
-            },
-            pages: PageCache::new(weak_self.clone(), 0),
-        })
+    pub fn new(ino: Ino, vfs: Weak<dyn Vfs>, size: usize, mode: Mode) -> Arc<Self> {
+        let inode = Arc::new_cyclic(|weak_self: &Weak<FileInode>| FileInode {
+            idata: InodeData::new(ino, vfs),
+            pages: PageCache::new(weak_self.clone()),
+        });
+
+        inode
+            .mode
+            .store(S_IFREG | (mode & 0o777), Ordering::Relaxed);
+        inode.nlink.store(1, Ordering::Relaxed);
+        inode.size.store(size as u64, Ordering::Relaxed);
+        inode
     }
 }
 
@@ -492,6 +499,10 @@ impl PageCacheBackend for FileInode {
     fn write_page(&self, _page: &CachePage, _offset: usize) -> KResult<usize> {
         Ok(PAGE_SIZE)
     }
+
+    fn size(&self) -> usize {
+        self.size.load(Ordering::Relaxed) as usize
+    }
 }
 
 impl Inode for FileInode {

+ 1 - 0
src/kernel/constants.rs

@@ -15,6 +15,7 @@ pub const SIG_SETMASK: u32 = 2;
 
 pub const CLOCK_REALTIME: u32 = 0;
 pub const CLOCK_MONOTONIC: u32 = 1;
+pub const CLOCK_REALTIME_COARSE: u32 = 5;
 
 pub const EPERM: u32 = 1;
 pub const ENOENT: u32 = 2;

+ 34 - 0
src/kernel/mem/mm_list.rs

@@ -6,6 +6,7 @@ use super::page_alloc::GlobalPageAlloc;
 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::{prelude::*, sync::ArcSwap};
 use alloc::collections::btree_set::BTreeSet;
 use core::fmt;
@@ -280,6 +281,25 @@ impl MMListInner<'_> {
 
 impl Drop for MMListInner<'_> {
     fn drop(&mut self) {
+        // May buggy
+        for area in &self.areas {
+            if area.is_shared {
+                for pte in self.page_table.iter_user(area.range()) {
+                    let (pfn, _) = pte.take();
+                    let raw_page = RawPagePtr::from(pfn);
+                    if raw_page.refcount().fetch_sub(1, Ordering::Relaxed) == 1 {
+                        // Wrong here
+                        // unsafe { Page::from_raw(pfn) };
+                    }
+                }
+            } else {
+                for pte in self.page_table.iter_user(area.range()) {
+                    let (pfn, _) = pte.take();
+                    unsafe { Page::from_raw(pfn) };
+                }
+            }
+        }
+
         // TODO: Recycle all pages in the page table.
     }
 }
@@ -349,6 +369,10 @@ impl MMList {
                     list_inner
                         .page_table
                         .set_copy_on_write(&mut inner.page_table, area.range());
+                } else {
+                    list_inner
+                        .page_table
+                        .set_copied(&mut inner.page_table, area.range());
                 }
             }
         }
@@ -699,6 +723,7 @@ trait PageTableExt {
     fn set_anonymous(&self, range: VRange, permission: Permission);
     fn set_mmapped(&self, range: VRange, permission: Permission);
     fn set_copy_on_write(&self, from: &Self, range: VRange);
+    fn set_copied(&self, from: &Self, range: VRange);
 }
 
 impl PageTableExt for KernelPageTable<'_> {
@@ -722,6 +747,15 @@ impl PageTableExt for KernelPageTable<'_> {
             to.set_copy_on_write(from);
         }
     }
+
+    fn set_copied(&self, from: &Self, range: VRange) {
+        let to_iter = self.iter_user(range);
+        let from_iter = from.iter_user(range);
+
+        for (to, from) in to_iter.zip(from_iter) {
+            *to = *from;
+        }
+    }
 }
 
 trait PTEExt {

+ 85 - 6
src/kernel/syscall/file_rw.rs

@@ -1,9 +1,12 @@
+use core::time::Duration;
+
 use super::FromSyscallArg;
 use crate::io::IntoStream;
 use crate::kernel::constants::{
-    EBADF, EFAULT, EINVAL, ENOENT, ENOTDIR, SEEK_CUR, SEEK_END, SEEK_SET, S_IFBLK, S_IFCHR,
+    EBADF, EFAULT, EINVAL, ENOENT, ENOSYS, ENOTDIR, SEEK_CUR, SEEK_END, SEEK_SET, S_IFBLK, S_IFCHR,
 };
 use crate::kernel::task::Thread;
+use crate::kernel::timer::sleep;
 use crate::kernel::vfs::filearray::FD;
 use crate::{
     io::{Buffer, BufferFill},
@@ -25,7 +28,8 @@ use eonix_runtime::task::Task;
 use posix_types::ctypes::{Long, PtrT};
 use posix_types::namei::RenameFlags;
 use posix_types::open::{AtFlags, OpenFlags};
-use posix_types::signal::SigSet;
+use posix_types::poll::FDSet;
+use posix_types::signal::{SigSet, Signal};
 use posix_types::stat::Stat;
 use posix_types::stat::{StatX, TimeSpec};
 use posix_types::syscall_no::*;
@@ -73,7 +77,20 @@ fn dentry_from(
 fn read(fd: FD, buffer: *mut u8, bufsize: usize) -> KResult<usize> {
     let mut buffer = UserBuffer::new(buffer, bufsize)?;
 
-    Task::block_on(thread.files.get(fd).ok_or(EBADF)?.read(&mut buffer))
+    Task::block_on(thread.files.get(fd).ok_or(EBADF)?.read(&mut buffer, None))
+}
+
+#[eonix_macros::define_syscall(SYS_PREAD64)]
+fn pread64(fd: FD, buffer: *mut u8, bufsize: usize, offset: usize) -> KResult<usize> {
+    let mut buffer = UserBuffer::new(buffer, bufsize)?;
+
+    Task::block_on(
+        thread
+            .files
+            .get(fd)
+            .ok_or(EBADF)?
+            .read(&mut buffer, Some(offset)),
+    )
 }
 
 #[eonix_macros::define_syscall(SYS_WRITE)]
@@ -81,7 +98,21 @@ fn write(fd: FD, buffer: *const u8, count: usize) -> KResult<usize> {
     let buffer = CheckedUserPointer::new(buffer, count)?;
     let mut stream = buffer.into_stream();
 
-    Task::block_on(thread.files.get(fd).ok_or(EBADF)?.write(&mut stream))
+    Task::block_on(thread.files.get(fd).ok_or(EBADF)?.write(&mut stream, None))
+}
+
+#[eonix_macros::define_syscall(SYS_PWRITE64)]
+fn pwrite64(fd: FD, buffer: *const u8, count: usize, offset: usize) -> KResult<usize> {
+    let buffer = CheckedUserPointer::new(buffer, count)?;
+    let mut stream = buffer.into_stream();
+
+    Task::block_on(
+        thread
+            .files
+            .get(fd)
+            .ok_or(EBADF)?
+            .write(&mut stream, Some(offset)),
+    )
 }
 
 #[eonix_macros::define_syscall(SYS_OPENAT)]
@@ -229,6 +260,12 @@ fn mkdir(pathname: *const u8, mode: u32) -> KResult<()> {
     sys_mkdirat(thread, FD::AT_FDCWD, pathname, mode)
 }
 
+#[eonix_macros::define_syscall(SYS_FTRUNCATE64)]
+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<()> {
@@ -353,7 +390,7 @@ fn readv(fd: FD, iov_user: *const IoVec, iovcnt: u32) -> KResult<usize> {
     let mut tot = 0usize;
     for mut buffer in iov_buffers.into_iter() {
         // TODO!!!: `readv`
-        let nread = Task::block_on(file.read(&mut buffer))?;
+        let nread = Task::block_on(file.read(&mut buffer, None))?;
         tot += nread;
 
         if nread != buffer.total() {
@@ -389,7 +426,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 = Task::block_on(file.write(&mut stream))?;
+        let nread = Task::block_on(file.write(&mut stream, None))?;
         tot += nread;
 
         if nread == 0 || !stream.is_drained() {
@@ -495,6 +532,48 @@ fn ppoll(
     do_poll(thread, fds, nfds, 0)
 }
 
+fn do_pselect(
+    nfds: u32,
+    readfds: *mut FDSet,
+    writefds: *mut FDSet,
+    exceptfds: *mut FDSet,
+    timeout: *const TimeSpec,
+    sigmask: *const SigSet,
+) {
+}
+
+#[eonix_macros::define_syscall(SYS_PSELECT6)]
+fn pselect6(
+    nfds: u32,
+    _readfds: *mut FDSet,
+    _writefds: *mut FDSet,
+    _exceptfds: *mut FDSet,
+    timeout: *mut TimeSpec,
+    _sigmask: *const (),
+) -> 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
+    // a non-NULL timeout as a fairly portable way to sleep with subsecond precision.
+    if nfds != 0 {
+        thread.raise(Signal::SIGSYS);
+        return Err(ENOSYS);
+    }
+
+    let timeout = UserPointerMut::new(timeout)?;
+    let timeout_value = timeout.read()?;
+
+    Task::block_on(sleep(Duration::from_millis(10)));
+
+    timeout.write(TimeSpec {
+        tv_sec: 0,
+        tv_nsec: 0,
+    })?;
+
+    // println_debug!("slept for {timeout_value:?}");
+
+    Ok(0)
+}
+
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_POLL)]
 fn poll(fds: *mut UserPollFd, nfds: u32, timeout: u32) -> KResult<u32> {

+ 30 - 21
src/kernel/syscall/mm.rs

@@ -29,12 +29,6 @@ impl FromSyscallArg for UserMmapFlags {
     }
 }
 
-impl FromSyscallArg for ShmFlags {
-    fn from_arg(value: usize) -> Self {
-        ShmFlags::from_bits_truncate(value as u32)
-    }
-}
-
 /// Check whether we are doing an implemented function.
 /// If `condition` is false, return `Err(err)`.
 #[allow(unused)]
@@ -73,7 +67,11 @@ fn do_mmap2(
             Mapping::Anonymous
         } else {
             // The mode is unimportant here, since we are checking prot in mm_area.
-            let shared_area = Task::block_on(SHM_MANAGER.lock()).create_shared_area(len, 0x777);
+            let shared_area = Task::block_on(SHM_MANAGER.lock()).create_shared_area(
+                len,
+                thread.process.pid,
+                0x777,
+            );
             Mapping::File(FileMapping::new(shared_area.area.clone(), 0, len))
         }
     } else {
@@ -96,11 +94,8 @@ 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) {
-        if prot.is_empty() {
-            Task::block_on(mm_list.protect(addr, len, permission)).map(|_| addr)
-        } else {
-            mm_list.mmap_fixed(addr, len, mapping, permission, is_shared)
-        }
+        Task::block_on(mm_list.unmap(addr, len));
+        mm_list.mmap_fixed(addr, len, mapping, permission, is_shared)
     } else {
         mm_list.mmap_hint(addr, len, mapping, permission, is_shared)
     };
@@ -118,7 +113,7 @@ fn mmap(
     fd: FD,
     offset: usize,
 ) -> KResult<usize> {
-    do_mmap2(thread, addr, len, prot, flags, fd, offset / PAGE_SIZE)
+    do_mmap2(thread, addr, len, prot, flags, fd, offset)
 }
 
 #[cfg(target_arch = "x86_64")]
@@ -177,14 +172,17 @@ fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(SYS_SHMGET)]
-fn shmget(key: usize, size: usize, shmflg: ShmFlags) -> KResult<u32> {
+fn shmget(key: usize, size: usize, shmflg: u32) -> KResult<u32> {
     let size = size.align_up(PAGE_SIZE);
 
     let mut shm_manager = Task::block_on(SHM_MANAGER.lock());
     let shmid = gen_shm_id(key)?;
 
+    let mode = shmflg & 0o777;
+    let shmflg = ShmFlags::from_bits_truncate(shmflg);
+
     if key == IPC_PRIVATE {
-        let new_shm = shm_manager.create_shared_area(size, shmflg.bits() & 0x777);
+        let new_shm = shm_manager.create_shared_area(size, thread.process.pid, mode);
         shm_manager.insert(shmid, new_shm);
         return Ok(shmid);
     }
@@ -198,7 +196,7 @@ fn shmget(key: usize, size: usize, shmflg: ShmFlags) -> KResult<u32> {
     }
 
     if shmflg.contains(ShmFlags::IPC_CREAT) {
-        let new_shm = shm_manager.create_shared_area(size, shmflg.bits() & 0x777);
+        let new_shm = shm_manager.create_shared_area(size, thread.process.pid, mode);
         shm_manager.insert(shmid, new_shm);
         return Ok(shmid);
     }
@@ -207,11 +205,14 @@ fn shmget(key: usize, size: usize, shmflg: ShmFlags) -> KResult<u32> {
 }
 
 #[eonix_macros::define_syscall(SYS_SHMAT)]
-fn shmat(shmid: u32, addr: usize, shmflg: ShmFlags) -> KResult<usize> {
+fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
     let mm_list = &thread.process.mm_list;
     let shm_manager = Task::block_on(SHM_MANAGER.lock());
     let shm_area = shm_manager.get(shmid).ok_or(EINVAL)?;
 
+    let mode = shmflg & 0o777;
+    let shmflg = ShmFlags::from_bits_truncate(shmflg);
+
     let mut permission = Permission {
         read: true,
         write: true,
@@ -225,10 +226,12 @@ fn shmat(shmid: u32, addr: usize, shmflg: ShmFlags) -> KResult<usize> {
         permission.write = false;
     }
 
+    let size = shm_area.shmid_ds.shm_segsz;
+
     let mapping = Mapping::File(FileMapping {
         file: shm_area.area.clone(),
         offset: 0,
-        length: shm_area.size,
+        length: size,
     });
 
     let addr = if addr != 0 {
@@ -236,12 +239,12 @@ fn shmat(shmid: u32, addr: usize, shmflg: ShmFlags) -> KResult<usize> {
             return Err(EINVAL);
         }
         let addr = VAddr::from(addr.align_down(PAGE_SIZE));
-        mm_list.mmap_fixed(addr, shm_area.size, mapping, permission, true)
+        mm_list.mmap_fixed(addr, size, mapping, permission, true)
     } else {
-        mm_list.mmap_hint(VAddr::NULL, shm_area.size, mapping, permission, true)
+        mm_list.mmap_hint(VAddr::NULL, size, mapping, permission, true)
     }?;
 
-    thread.process.shm_areas.lock().insert(addr, shm_area.size);
+    thread.process.shm_areas.lock().insert(addr, size);
 
     Ok(addr.addr())
 }
@@ -252,9 +255,15 @@ fn shmdt(addr: usize) -> KResult<usize> {
     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 Task::block_on(thread.process.mm_list.unmap(addr, size)).map(|_| 0);
 }
 
+#[eonix_macros::define_syscall(SYS_SHMCTL)]
+fn shmctl(shmid: u32, op: i32, shmid_ds: usize) -> KResult<usize> {
+    Ok(0)
+}
+
 #[eonix_macros::define_syscall(SYS_MEMBARRIER)]
 fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
     Ok(())

+ 62 - 1
src/kernel/syscall/procops.rs

@@ -1,6 +1,8 @@
 use super::SyscallNoReturn;
 use crate::io::Buffer;
-use crate::kernel::constants::{EINVAL, ENOENT, ENOTDIR, ERANGE, ESRCH};
+use crate::kernel::constants::{
+    CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_REALTIME_COARSE, EINVAL, ENOENT, ENOTDIR, ERANGE, ESRCH,
+};
 use crate::kernel::constants::{
     ENOSYS, PR_GET_NAME, PR_SET_NAME, RLIMIT_STACK, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK,
 };
@@ -23,6 +25,7 @@ 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_runtime::task::Task;
 use eonix_sync::AsProof as _;
@@ -66,6 +69,37 @@ fn nanosleep(req: *const (u32, u32), rem: *mut (u32, u32)) -> KResult<usize> {
     Ok(0)
 }
 
+#[eonix_macros::define_syscall(SYS_CLOCK_NANOSLEEP)]
+fn clock_nanosleep(
+    clock_id: u32,
+    flags: u32,
+    req: *const (u32, u32),
+    rem: *mut (u32, u32),
+) -> KResult<usize> {
+    if clock_id != CLOCK_REALTIME
+        && clock_id != CLOCK_REALTIME_COARSE
+        && clock_id != CLOCK_MONOTONIC
+    {
+        unimplemented!("Unsupported clock_id: {}", clock_id);
+    }
+
+    let req = UserPointer::new(req)?.read()?;
+    let rem = if rem.is_null() {
+        None
+    } else {
+        Some(UserPointerMut::new(rem)?)
+    };
+
+    let duration = Duration::from_secs(req.0 as u64) + Duration::from_nanos(req.1 as u64);
+    Task::block_on(sleep(duration));
+
+    if let Some(rem) = rem {
+        rem.write((0, 0))?;
+    }
+
+    Ok(0)
+}
+
 #[eonix_macros::define_syscall(SYS_UMASK)]
 fn umask(mask: u32) -> KResult<u32> {
     let mut umask = thread.fs_context.umask.lock();
@@ -181,6 +215,9 @@ fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<Sysc
     thread.set_name(dentry.get_name());
 
     let mut trap_ctx = thread.trap_ctx.borrow();
+    *trap_ctx = TrapContext::new();
+    trap_ctx.set_user_mode(true);
+    trap_ctx.set_interrupt_enabled(true);
     trap_ctx.set_program_counter(load_info.entry_ip.addr());
     trap_ctx.set_stack_pointer(load_info.sp.addr());
 
@@ -409,6 +446,30 @@ fn getgid() -> KResult<u32> {
     Ok(0)
 }
 
+#[eonix_macros::define_syscall(SYS_GETEGID)]
+fn getegid() -> KResult<u32> {
+    // All users are root for now.
+    Ok(0)
+}
+
+#[eonix_macros::define_syscall(SYS_GETRANDOM)]
+fn getrandom() -> KResult<u32> {
+    // All users are root for now.
+    Ok(0)
+}
+
+#[eonix_macros::define_syscall(SYS_SYNC)]
+fn sync() -> KResult<u32> {
+    // All users are root for now.
+    Ok(0)
+}
+
+#[eonix_macros::define_syscall(SYS_FSYNC)]
+fn fsync() -> KResult<u32> {
+    // All users are root for now.
+    Ok(0)
+}
+
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_GETGID32)]
 fn getgid32() -> KResult<u32> {

+ 5 - 2
src/kernel/syscall/sysinfo.rs

@@ -1,6 +1,6 @@
 use crate::{
     kernel::{
-        constants::{CLOCK_MONOTONIC, CLOCK_REALTIME, EINVAL},
+        constants::{CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_REALTIME_COARSE, EINVAL},
         task::Thread,
         timer::{Instant, Ticks},
         user::UserPointerMut,
@@ -78,7 +78,10 @@ fn gettimeofday(timeval: *mut TimeVal, timezone: *mut ()) -> KResult<()> {
 }
 
 fn do_clock_gettime64(_thread: &Thread, clock_id: u32, timespec: *mut TimeSpec) -> KResult<()> {
-    if clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC {
+    if clock_id != CLOCK_REALTIME
+        && clock_id != CLOCK_REALTIME_COARSE
+        && clock_id != CLOCK_MONOTONIC
+    {
         unimplemented!("Unsupported clock_id: {}", clock_id);
     }
 

+ 1 - 1
src/kernel/timer.rs

@@ -18,7 +18,7 @@ static SLEEPERS_LIST: Spin<BinaryHeap<Reverse<Sleepers>>> = Spin::new(BinaryHeap
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Ticks(usize);
 
-#[derive(Default, Clone, Copy)]
+#[derive(Debug, Default, Clone, Copy)]
 pub struct Instant {
     secs_since_epoch: u64,
     nsecs_within: u32,

+ 29 - 13
src/kernel/vfs/file.rs

@@ -334,7 +334,7 @@ impl InodeFile {
         Ok(new_cursor)
     }
 
-    fn write(&self, stream: &mut dyn Stream) -> KResult<usize> {
+    fn write(&self, stream: &mut dyn Stream, offset: Option<usize>) -> KResult<usize> {
         if !self.write {
             return Err(EBADF);
         }
@@ -346,23 +346,35 @@ impl InodeFile {
 
             Ok(nwrote)
         } else {
-            let nwrote = self.dentry.write(stream, WriteOffset::Position(*cursor))?;
+            let nwrote = if let Some(offset) = offset {
+                self.dentry.write(stream, WriteOffset::Position(offset))?
+            } else {
+                let nwrote = self.dentry.write(stream, WriteOffset::Position(*cursor))?;
+                *cursor += nwrote;
+                nwrote
+            };
 
-            *cursor += nwrote;
             Ok(nwrote)
         }
     }
 
-    fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
+    fn read(&self, buffer: &mut dyn Buffer, offset: Option<usize>) -> KResult<usize> {
         if !self.read {
             return Err(EBADF);
         }
 
-        let mut cursor = Task::block_on(self.cursor.lock());
+        let nread = if let Some(offset) = offset {
+            let nread = self.dentry.read(buffer, offset)?;
+            nread
+        } else {
+            let mut cursor = Task::block_on(self.cursor.lock());
 
-        let nread = self.dentry.read(buffer, *cursor)?;
+            let nread = self.dentry.read(buffer, *cursor)?;
+
+            *cursor += nread;
+            nread
+        };
 
-        *cursor += nread;
         Ok(nread)
     }
 
@@ -466,9 +478,9 @@ impl TerminalFile {
 }
 
 impl FileType {
-    pub async fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
+    pub async fn read(&self, buffer: &mut dyn Buffer, offset: Option<usize>) -> KResult<usize> {
         match self {
-            FileType::Inode(inode) => inode.read(buffer),
+            FileType::Inode(inode) => inode.read(buffer, offset),
             FileType::PipeRead(pipe) => pipe.pipe.read(buffer).await,
             FileType::TTY(tty) => tty.read(buffer).await,
             FileType::CharDev(device) => device.read(buffer),
@@ -491,9 +503,9 @@ impl FileType {
     //     }
     // }
 
-    pub async fn write(&self, stream: &mut dyn Stream) -> KResult<usize> {
+    pub async fn write(&self, stream: &mut dyn Stream, offset: Option<usize>) -> KResult<usize> {
         match self {
-            FileType::Inode(inode) => inode.write(stream),
+            FileType::Inode(inode) => inode.write(stream, offset),
             FileType::PipeWrite(pipe) => pipe.pipe.write(stream).await,
             FileType::TTY(tty) => tty.write(stream),
             FileType::CharDev(device) => device.write(stream),
@@ -537,12 +549,16 @@ impl FileType {
             if Thread::current().signal_list.has_pending_signal() {
                 return if cur == 0 { Err(EINTR) } else { Ok(cur) };
             }
-            let nread = self.read(&mut ByteBuffer::new(&mut buffer[..len])).await?;
+            let nread = self
+                .read(&mut ByteBuffer::new(&mut buffer[..len]), None)
+                .await?;
             if nread == 0 {
                 break;
             }
 
-            let nwrote = dest_file.write(&mut buffer[..nread].into_stream()).await?;
+            let nwrote = dest_file
+                .write(&mut buffer[..nread].into_stream(), None)
+                .await?;
             nsent += nwrote;
 
             if nwrote != len {

+ 1 - 0
src/kernel/vfs/inode.rs

@@ -35,6 +35,7 @@ pub type AtomicGid = AtomicU32;
 pub type Mode = u32;
 pub type AtomicMode = AtomicU32;
 
+#[derive(Debug)]
 pub struct InodeData {
     pub ino: Ino,
     pub size: AtomicISize,