Explorar o código

Merge pull request #43 from greatbridf/comp-fix-syscall

Fix various syscalls and loongarch64 platform impl for the os comp 2025
greatbridf hai 6 meses
pai
achega
9e7e047578

+ 5 - 5
Cargo.toml

@@ -51,19 +51,19 @@ debug = true
 panic = "abort"
 
 [profile.dev.package.eonix_preempt]
-opt-level = 2
+opt-level = "s"
 
 [profile.dev.package.eonix_runtime]
-opt-level = 2
+opt-level = "s"
 
 [profile.dev.package.eonix_sync]
-opt-level = 2
+opt-level = "s"
 
 [profile.dev.package.intrusive_list]
-opt-level = 2
+opt-level = "s"
 
 [profile.dev.package.eonix_hal]
-opt-level = 2
+opt-level = "s"
 
 [profile.dev.package."*"]
 opt-level = "s"

+ 12 - 6
configure

@@ -1,6 +1,12 @@
 #!/bin/sh
 DEFAULT_ARCH="x86_64"
 
+if [ "$OUT" = "" ]; then
+    OUT="Makefile"
+fi
+
+printf "Configuring for %s...\n" "$OUT"
+
 event() {
     printf "$1... "
 }
@@ -119,10 +125,10 @@ else
     echo "$IMG"
 fi
 
-cp Makefile.src Makefile
-sed -i '' -e "s|##DEFAULT_ARCH##|$DEFAULT_ARCH|" Makefile > /dev/null 2>&1
-sed -i '' -e "s|##GDB##|$GDB|" Makefile > /dev/null 2>&1
-sed -i '' -e "s|##QEMU##|$QEMU|" Makefile > /dev/null 2>&1
-sed -i '' -e "s|##FDISK##|$FDISK|" Makefile > /dev/null 2>&1
-sed -i '' -e "s|##IMAGE##|$IMG|" Makefile > /dev/null 2>&1
+cp Makefile.src "$OUT"
+sed -i '' -e "s|##DEFAULT_ARCH##|$DEFAULT_ARCH|" "$OUT" > /dev/null 2>&1
+sed -i '' -e "s|##GDB##|$GDB|" "$OUT" > /dev/null 2>&1
+sed -i '' -e "s|##QEMU##|$QEMU|" "$OUT" > /dev/null 2>&1
+sed -i '' -e "s|##FDISK##|$FDISK|" "$OUT" > /dev/null 2>&1
+sed -i '' -e "s|##IMAGE##|$IMG|" "$OUT" > /dev/null 2>&1
 exit 0

+ 24 - 2
crates/eonix_hal/src/arch/loongarch64/bootstrap.rs

@@ -1,4 +1,5 @@
 use super::cpu::CPUID;
+use super::cpu::CPU_COUNT;
 use crate::{
     arch::{
         cpu::CPU,
@@ -16,7 +17,7 @@ use core::{
     alloc::Allocator,
     arch::asm,
     cell::RefCell,
-    sync::atomic::{AtomicBool, AtomicUsize},
+    sync::atomic::{AtomicBool, AtomicUsize, Ordering},
 };
 use eonix_hal_traits::mm::Memory;
 use eonix_mm::{
@@ -25,6 +26,9 @@ use eonix_mm::{
     paging::{Page, PageAccess, PageAlloc, PAGE_SIZE, PFN},
 };
 use eonix_percpu::PercpuArea;
+use loongArch64::register::ecfg;
+use loongArch64::register::ecfg::LineBasedInterrupt;
+use loongArch64::register::tcfg;
 use loongArch64::register::{euen, pgdl};
 
 #[unsafe(link_section = ".bootstrap.stack")]
@@ -225,6 +229,8 @@ fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
     euen::set_fpe(true);
     euen::set_sxe(true);
 
+    CPU_COUNT.fetch_add(1, Ordering::Relaxed);
+
     let mut percpu_area = PercpuArea::new(|layout| {
         let page_count = layout.size().div_ceil(PAGE_SIZE);
         let page = Page::alloc_at_least_in(page_count, alloc);
@@ -264,8 +270,24 @@ fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
         )
     }
 
-    // todo!("set_next_timer()");
+    let timer_frequency = loongArch64::time::get_timer_freq();
+
+    // 1ms periodic timer.
+    tcfg::set_init_val(timer_frequency / 1_000);
+    tcfg::set_periodic(true);
+    tcfg::set_en(true);
+
+    ecfg::set_lie(LineBasedInterrupt::all());
 }
 
 /// TODO
 fn bootstrap_smp(alloc: impl Allocator, page_alloc: &RefCell<BasicPageAlloc>) {}
+
+pub fn shutdown() -> ! {
+    let ged_addr = PAddr::from(0x100E001C);
+    unsafe {
+        let ged_ptr = ArchPhysAccess::as_ptr::<u8>(ged_addr);
+        ged_ptr.write_volatile(0x34);
+        loop {}
+    }
+}

+ 3 - 0
crates/eonix_hal/src/arch/loongarch64/cpu.rs

@@ -1,8 +1,11 @@
 use super::trap::setup_trap;
+use core::sync::atomic::AtomicUsize;
 use core::{arch::asm, pin::Pin, ptr::NonNull};
 use eonix_preempt::PreemptGuard;
 use eonix_sync_base::LazyLock;
 
+pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
+
 #[eonix_percpu::define_percpu]
 pub static CPUID: usize = 0;
 

+ 2 - 1
crates/eonix_hal/src/arch/loongarch64/trap/trap_context.rs

@@ -8,6 +8,7 @@ use eonix_mm::address::VAddr;
 use loongArch64::register::{
     badv,
     estat::{Estat, Exception, Interrupt, Trap},
+    ticlr,
 };
 
 #[repr(C)]
@@ -145,7 +146,7 @@ impl RawTrapContext for TrapContext {
         match self.estat.cause() {
             Trap::Interrupt(Interrupt::Timer) => TrapType::Timer {
                 callback: |handler| {
-                    todo!("set_next_timer()");
+                    ticlr::clear_timer_interrupt();
                     handler();
                 },
             },

+ 7 - 1
crates/eonix_hal/src/arch/riscv64/bootstrap.rs

@@ -1,7 +1,7 @@
 use super::{
     config::{self, mm::*},
     console::write_str,
-    cpu::CPUID,
+    cpu::{CPUID, CPU_COUNT},
     time::set_next_timer,
     trap::TRAP_SCRATCH,
 };
@@ -202,6 +202,8 @@ fn setup_kernel_page_table(alloc: impl PageAlloc) {
 
 /// set up tp register to percpu
 fn setup_cpu(alloc: impl PageAlloc, hart_id: usize) {
+    CPU_COUNT.fetch_add(1, Ordering::Relaxed);
+
     let mut percpu_area = PercpuArea::new(|layout| {
         let page_count = layout.size().div_ceil(PAGE_SIZE);
         let page = Page::alloc_at_least_in(page_count, alloc);
@@ -393,3 +395,7 @@ pub fn early_console_write(s: &str) {
 pub fn early_console_putchar(ch: u8) {
     console_putchar(ch);
 }
+
+pub fn shutdown() -> ! {
+    sbi::legacy::shutdown();
+}

+ 3 - 1
crates/eonix_hal/src/arch/riscv64/cpu.rs

@@ -3,7 +3,7 @@ use super::{
     trap::{setup_trap, TRAP_SCRATCH},
 };
 use crate::arch::fdt::{FdtExt, FDT};
-use core::{arch::asm, pin::Pin, ptr::NonNull};
+use core::{arch::asm, pin::Pin, ptr::NonNull, sync::atomic::AtomicUsize};
 use eonix_preempt::PreemptGuard;
 use eonix_sync_base::LazyLock;
 use riscv::register::{
@@ -12,6 +12,8 @@ use riscv::register::{
 };
 use sbi::PhysicalAddress;
 
+pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
+
 #[eonix_percpu::define_percpu]
 pub static CPUID: usize = 0;
 

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

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

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

@@ -70,7 +70,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;
@@ -289,7 +289,6 @@ pub const SYS_TIMER_SETTIME: usize = 409;
 pub const SYS_TIMERFD_GETTIME: usize = 410;
 pub const SYS_TIMERFD_SETTIME: usize = 411;
 pub const SYS_UTIMENSAT_TIME64: usize = 412;
-pub const SYS_PSELECT6: usize = 413;
 pub const SYS_PPOLL_TIME64: usize = 414;
 pub const SYS_IO_PGETEVENTS: usize = 416;
 pub const SYS_RECVMMSG: usize = 417;

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

@@ -98,7 +98,7 @@ pub const SYS_EXIT_GROUP: usize = 94;
 pub const SYS_WAITID: usize = 95;
 pub const SYS_SET_TID_ADDRESS: usize = 96;
 pub const SYS_UNSHARE: usize = 97;
-pub const SYS_FUTEX: usize = 422;
+pub const SYS_FUTEX: usize = 98;
 pub const SYS_SET_ROBUST_LIST: usize = 99;
 pub const SYS_GET_ROBUST_LIST: usize = 100;
 pub const SYS_NANOSLEEP: usize = 101;

+ 4 - 1
script/build-img.sh

@@ -1,7 +1,10 @@
 #!/bin/sh
 
 OS=`uname -s`
-SUDO=sudo
+
+if sudo --version > /dev/null 2>&1; then
+    SUDO=sudo
+fi
 
 if [ "$OUTPUT" = "" ]; then
     OUTPUT="build/fs-$ARCH.img"

+ 50 - 48
src/kernel/mem/mm_area.rs

@@ -2,10 +2,10 @@ 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::mem::page_cache::PageCacheRawPage;
-use crate::KResult;
-use core::sync::atomic;
-use core::{borrow::Borrow, cell::UnsafeCell, cmp};
+use crate::prelude::KResult;
+use core::borrow::Borrow;
+use core::cell::UnsafeCell;
+use core::cmp;
 use eonix_mm::address::{AddrOps as _, VAddr, VRange};
 use eonix_mm::page_table::{PageAttribute, RawAttribute, PTE};
 use eonix_mm::paging::{PAGE_SIZE, PFN};
@@ -145,53 +145,55 @@ impl MMArea {
 
         let file_offset = file_mapping.offset + offset;
         let cnt_to_read = (file_mapping.length - offset).min(0x1000);
-        let raw_page = page_cache.get_page(file_offset).await?.ok_or(EINVAL)?;
-
-        // Non-write faults: we find page in pagecache and do mapping
-        // Write fault: we need to care about shared or private mapping.
-        if !write {
-            // Bss is embarrassing in pagecache!
-            // We have to assume cnt_to_read < PAGE_SIZE all bss
-            if cnt_to_read < PAGE_SIZE {
-                let new_page = Page::zeroed();
-                unsafe {
-                    let page_data = new_page.as_memblk().as_bytes_mut();
-                    page_data[..cnt_to_read]
-                        .copy_from_slice(&raw_page.as_memblk().as_bytes()[..cnt_to_read]);
-                }
-                *pfn = new_page.into_raw();
-            } else {
-                raw_page.refcount().fetch_add(1, atomic::Ordering::Relaxed);
-                *pfn = Into::<PFN>::into(raw_page);
-            }
 
-            if self.permission.write {
-                if self.is_shared {
-                    // The page may will not be written,
-                    // But we simply assume page will be dirty
-                    raw_page.set_dirty();
-                    attr.insert(PageAttribute::WRITE);
+        page_cache
+            .with_page(file_offset, |page, cache_page| {
+                // Non-write faults: we find page in pagecache and do mapping
+                // Write fault: we need to care about shared or private mapping.
+                if !write {
+                    // Bss is embarrassing in pagecache!
+                    // We have to assume cnt_to_read < PAGE_SIZE all bss
+                    if cnt_to_read < PAGE_SIZE {
+                        let new_page = Page::zeroed();
+                        unsafe {
+                            let page_data = new_page.as_memblk().as_bytes_mut();
+                            page_data[..cnt_to_read]
+                                .copy_from_slice(&page.as_memblk().as_bytes()[..cnt_to_read]);
+                        }
+                        *pfn = new_page.into_raw();
+                    } else {
+                        *pfn = page.clone().into_raw();
+                    }
+
+                    if self.permission.write {
+                        if self.is_shared {
+                            // The page may will not be written,
+                            // But we simply assume page will be dirty
+                            cache_page.set_dirty();
+                            attr.insert(PageAttribute::WRITE);
+                        } else {
+                            attr.insert(PageAttribute::COPY_ON_WRITE);
+                        }
+                    }
                 } else {
-                    attr.insert(PageAttribute::COPY_ON_WRITE);
-                }
-            }
-        } else {
-            if self.is_shared {
-                raw_page.refcount().fetch_add(1, atomic::Ordering::Relaxed);
-                raw_page.set_dirty();
-                *pfn = Into::<PFN>::into(raw_page);
-            } else {
-                let new_page = Page::zeroed();
-                unsafe {
-                    let page_data = new_page.as_memblk().as_bytes_mut();
-                    page_data[..cnt_to_read]
-                        .copy_from_slice(&raw_page.as_memblk().as_bytes()[..cnt_to_read]);
-                }
-                *pfn = new_page.into_raw();
-            }
+                    if self.is_shared {
+                        cache_page.set_dirty();
+                        *pfn = page.clone().into_raw();
+                    } else {
+                        let new_page = Page::zeroed();
+                        unsafe {
+                            let page_data = new_page.as_memblk().as_bytes_mut();
+                            page_data[..cnt_to_read]
+                                .copy_from_slice(&page.as_memblk().as_bytes()[..cnt_to_read]);
+                        }
+                        *pfn = new_page.into_raw();
+                    }
 
-            attr.insert(PageAttribute::WRITE);
-        }
+                    attr.insert(PageAttribute::WRITE);
+                }
+            })
+            .await?
+            .ok_or(EINVAL)?;
 
         attr.insert(PageAttribute::PRESENT);
         attr.remove(PageAttribute::MAPPED);

+ 2 - 9
src/kernel/mem/page_alloc/raw_page.rs

@@ -1,5 +1,5 @@
-use crate::kernel::mem::{page_cache::PageCacheRawPage, MemoryBlock};
-use crate::kernel::mem::{AsMemoryBlock, PhysAccess};
+use crate::kernel::mem::page_cache::PageCacheRawPage;
+use crate::kernel::mem::PhysAccess;
 use buddy_allocator::BuddyRawPage;
 use core::{
     ptr::NonNull,
@@ -271,10 +271,3 @@ impl PageCacheRawPage for RawPagePtr {
         self.as_mut().shared_data = PageType::PageCache(PageCacheInner { valid_size: 0 });
     }
 }
-
-/// SAFETY: `RawPagePtr` is a pointer to a valid `RawPage` struct.
-impl AsMemoryBlock for RawPagePtr {
-    fn as_memblk(&self) -> MemoryBlock {
-        unsafe { MemoryBlock::new(self.real_ptr::<()>().addr(), PAGE_SIZE) }
-    }
-}

+ 43 - 22
src/kernel/mem/page_cache.rs

@@ -1,4 +1,4 @@
-use super::access::AsMemoryBlock;
+use super::{paging::AllocZeroed, Page};
 use crate::{
     io::{Buffer, FillResult, Stream},
     kernel::mem::page_alloc::RawPagePtr,
@@ -7,7 +7,12 @@ use crate::{
 };
 use align_ext::AlignExt;
 use alloc::{collections::btree_map::BTreeMap, sync::Weak};
-use eonix_mm::paging::{PageAlloc, RawPage, PAGE_SIZE, PAGE_SIZE_BITS};
+use core::mem::ManuallyDrop;
+use eonix_hal::mm::ArchPhysAccess;
+use eonix_mm::{
+    address::{PAddr, PhysAccess},
+    paging::{PageAlloc, RawPage, PAGE_SIZE, PAGE_SIZE_BITS, PFN},
+};
 use eonix_sync::Mutex;
 
 pub struct PageCache {
@@ -58,13 +63,11 @@ impl CachePage {
     }
 
     pub fn new_zeroed() -> Self {
-        let page = GlobalPageAlloc.alloc().unwrap();
-        // SAFETY: We own the page exclusively, so we can safely zero it.
-        unsafe {
-            page.as_memblk().as_bytes_mut().fill(0);
-        }
-        page.cache_init();
-        Self(page)
+        let page = Page::zeroed();
+        let raw_page_ptr = RawPagePtr::from(page.into_raw());
+
+        raw_page_ptr.cache_init();
+        Self(raw_page_ptr)
     }
 
     pub fn valid_size(&self) -> usize {
@@ -77,13 +80,21 @@ impl CachePage {
 
     pub fn all(&self) -> &[u8] {
         unsafe {
-            self.0.as_memblk().as_bytes()
+            core::slice::from_raw_parts(
+                // SAFETY: The page is exclusively owned by us, so we can safely access its data.
+                ArchPhysAccess::as_ptr(PAddr::from(PFN::from(self.0))).as_ptr(),
+                PAGE_SIZE,
+            )
         }
     }
 
     pub fn all_mut(&mut self) -> &mut [u8] {
         unsafe {
-            self.0.as_memblk().as_bytes_mut()
+            core::slice::from_raw_parts_mut(
+                // SAFETY: The page is exclusively owned by us, so we can safely access its data.
+                ArchPhysAccess::as_ptr(PAddr::from(PFN::from(self.0))).as_ptr(),
+                PAGE_SIZE,
+            )
         }
     }
 
@@ -247,7 +258,10 @@ impl PageCache {
         Ok(())
     }
 
-    pub async fn get_page(&self, offset: usize) -> KResult<Option<RawPagePtr>> {
+    pub async fn with_page<F, O>(&self, offset: usize, func: F) -> KResult<Option<O>>
+    where
+        F: FnOnce(&Page, &CachePage) -> O,
+    {
         let offset_aligin = offset.align_down(PAGE_SIZE);
         let page_id = offset_aligin >> PAGE_SIZE_BITS;
         let size = self.backend.upgrade().unwrap().size();
@@ -258,16 +272,23 @@ impl PageCache {
 
         let mut pages = self.pages.lock().await;
 
-        if let Some(page) = pages.get(&page_id) {
-            Ok(Some(page.0))
-        } else {
-            let mut new_page = CachePage::new();
-            self.backend
-                .upgrade()
-                .unwrap()
-                .read_page(&mut new_page, offset_aligin)?;
-            pages.insert(page_id, new_page);
-            Ok(Some(new_page.0))
+        let raw_page_ptr = match pages.get(&page_id) {
+            Some(CachePage(raw_page_ptr)) => *raw_page_ptr,
+            None => {
+                let mut new_page = CachePage::new();
+                self.backend
+                    .upgrade()
+                    .unwrap()
+                    .read_page(&mut new_page, offset_aligin)?;
+                pages.insert(page_id, new_page);
+                new_page.0
+            }
+        };
+
+        unsafe {
+            let page = ManuallyDrop::new(Page::from_raw_unchecked(PFN::from(raw_page_ptr)));
+
+            Ok(Some(func(&page, &CachePage(raw_page_ptr))))
         }
     }
 }

+ 12 - 0
src/kernel/syscall.rs

@@ -62,6 +62,18 @@ impl SyscallRetVal for usize {
     }
 }
 
+impl SyscallRetVal for isize {
+    fn into_retval(self) -> Option<usize> {
+        Some(self as usize)
+    }
+}
+
+impl SyscallRetVal for i32 {
+    fn into_retval(self) -> Option<usize> {
+        Some(self as usize)
+    }
+}
+
 impl SyscallRetVal for SyscallNoReturn {
     fn into_retval(self) -> Option<usize> {
         None

+ 71 - 3
src/kernel/syscall/procops.rs

@@ -8,12 +8,12 @@ use crate::kernel::constants::{
 };
 use crate::kernel::mem::PageBuffer;
 use crate::kernel::task::{
-    do_clone, futex_wait, futex_wake, FutexFlags, FutexOp, ProcessList, ProgramLoader,
+    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::{CheckedUserPointer, UserString};
+use crate::kernel::user::dataflow::UserString;
 use crate::kernel::user::{UserPointer, UserPointerMut};
 use crate::kernel::vfs::{self, dentry::Dentry};
 use crate::path::Path;
@@ -139,9 +139,21 @@ fn chdir(path: *const u8) -> KResult<()> {
     Ok(())
 }
 
+#[eonix_macros::define_syscall(SYS_UMOUNT)]
+fn umount(source: *const u8) -> KResult<()> {
+    let source = UserString::new(source)?;
+    if source.as_cstr().to_str().unwrap() == "./mnt" {
+        return Ok(());
+    }
+    return Err(ENOENT);
+}
+
 #[eonix_macros::define_syscall(SYS_MOUNT)]
 fn mount(source: *const u8, target: *const u8, fstype: *const u8, flags: usize) -> KResult<()> {
     let source = UserString::new(source)?;
+    if source.as_cstr().to_str().unwrap() == "/dev/vda2" {
+        return Ok(());
+    }
     let target = UserString::new(target)?;
     let fstype = UserString::new(fstype)?;
 
@@ -445,6 +457,29 @@ 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
+}
+
+#[eonix_macros::define_syscall(SYS_SCHED_YIELD)]
+fn sched_yield() -> KResult<()> {
+    Task::block_on(yield_now());
+    Ok(())
+}
+
 #[eonix_macros::define_syscall(SYS_SYNC)]
 fn sync() -> KResult<()> {
     Ok(())
@@ -616,6 +651,29 @@ fn rt_sigprocmask(
     Ok(())
 }
 
+#[repr(C)]
+#[derive(Clone, Copy)]
+struct TimeSpec32 {
+    tv_sec: i32,
+    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,
+) -> KResult<i32> {
+    // TODO
+    Ok(0)
+}
+
 #[eonix_macros::define_syscall(SYS_RT_SIGACTION)]
 fn rt_sigaction(
     signum: u32,
@@ -671,7 +729,12 @@ fn prlimit64(
             }
 
             if !new_limit.is_null() {
-                return Err(ENOSYS);
+                let new_rlimit = UserPointer::new(new_limit)?.read()?;
+                if new_rlimit.rlim_cur > new_rlimit.rlim_max {
+                    return Err(EINVAL);
+                }
+                // TODO:
+                // thread.process().set_rlimit(resource, new_rlimit)?;
             }
             Ok(())
         }
@@ -684,6 +747,11 @@ fn getrlimit(resource: u32, rlimit: *mut RLimit) -> KResult<()> {
     sys_prlimit64(thread, 0, resource, core::ptr::null(), rlimit)
 }
 
+#[eonix_macros::define_syscall(SYS_SETRLIMIT)]
+fn setrlimit(resource: u32, rlimit: *const RLimit) -> KResult<()> {
+    sys_prlimit64(thread, 0, resource, rlimit, core::ptr::null_mut())
+}
+
 #[repr(C)]
 #[derive(Clone, Copy)]
 struct RUsage {

+ 18 - 13
src/kernel/syscall/sysinfo.rs

@@ -82,21 +82,26 @@ 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_REALTIME_COARSE
-        && clock_id != CLOCK_MONOTONIC
-    {
-        unimplemented!("Unsupported clock_id: {}", clock_id);
-    }
-
     let timespec = UserPointerMut::new(timespec)?;
-    let now = Instant::now();
-    let since_epoch = now.since_epoch();
 
-    timespec.write(TimeSpec {
-        tv_sec: since_epoch.as_secs(),
-        tv_nsec: since_epoch.subsec_nanos(),
-    })
+    match clock_id {
+        CLOCK_REALTIME | CLOCK_REALTIME_COARSE => {
+            let now = Instant::now();
+            let since_epoch = now.since_epoch();
+            timespec.write(TimeSpec {
+                tv_sec: since_epoch.as_secs(),
+                tv_nsec: since_epoch.subsec_nanos(),
+            })
+        }
+        CLOCK_MONOTONIC => {
+            let uptime_secs = Ticks::since_boot().as_secs();
+            timespec.write(TimeSpec {
+                tv_sec: uptime_secs,
+                tv_nsec: 0,
+            })
+        }
+        clock_id => unimplemented!("Unsupported clock_id: {}", clock_id),
+    }
 }
 
 #[cfg(not(target_arch = "x86_64"))]

+ 1 - 1
src/kernel/task.rs

@@ -18,4 +18,4 @@ pub use process_group::ProcessGroup;
 pub use process_list::ProcessList;
 pub use session::Session;
 pub use signal::SignalAction;
-pub use thread::{new_thread_runnable, Thread, ThreadBuilder};
+pub use thread::{new_thread_runnable, yield_now, Thread, ThreadBuilder};

+ 1 - 1
src/kernel/task/thread.rs

@@ -446,7 +446,7 @@ impl Thread {
     }
 }
 
-async fn yield_now() {
+pub async fn yield_now() {
     struct Yield {
         yielded: bool,
     }

+ 18 - 2
src/lib.rs

@@ -26,7 +26,10 @@ use core::{
     hint::spin_loop,
     sync::atomic::{AtomicBool, Ordering},
 };
-use eonix_hal::{processor::CPU, traits::trap::IrqState, trap::disable_irqs_save};
+use eonix_hal::{
+    arch_exported::bootstrap::shutdown, processor::CPU, traits::trap::IrqState,
+    trap::disable_irqs_save,
+};
 use eonix_mm::address::PRange;
 use eonix_runtime::{run::FutureRun, scheduler::Scheduler, task::Task};
 use kernel::{
@@ -45,6 +48,19 @@ use kernel_init::setup_memory;
 use path::Path;
 use prelude::*;
 
+#[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))]
+fn do_panic() -> ! {
+    shutdown();
+}
+
+#[cfg(not(any(target_arch = "riscv64", target_arch = "loongarch64")))]
+fn do_panic() -> ! {
+    // Spin forever.
+    loop {
+        spin_loop();
+    }
+}
+
 #[panic_handler]
 fn panic(info: &core::panic::PanicInfo) -> ! {
     if let Some(location) = info.location() {
@@ -60,7 +76,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
     println_fatal!();
     println_fatal!("{}", info.message());
 
-    loop {}
+    do_panic()
 }
 
 static BSP_OK: AtomicBool = AtomicBool::new(false);

+ 6 - 6
user-programs/init_script_riscv64.sh

@@ -23,9 +23,9 @@ do_or_freeze $BUSYBOX mkdir -p /dev
 do_or_freeze $BUSYBOX mknod -m 666 /dev/console c 5 1
 do_or_freeze $BUSYBOX mknod -m 666 /dev/null c 1 3
 do_or_freeze $BUSYBOX mknod -m 666 /dev/zero c 1 5
-do_or_freeze $BUSYBOX mknod -m 666 /dev/sda b 8 0
-do_or_freeze $BUSYBOX mknod -m 666 /dev/sda1 b 8 1
-do_or_freeze $BUSYBOX mknod -m 666 /dev/sdb b 8 16
+do_or_freeze $BUSYBOX mknod -m 666 /dev/vda b 8 0
+do_or_freeze $BUSYBOX mknod -m 666 /dev/vda1 b 8 1
+do_or_freeze $BUSYBOX mknod -m 666 /dev/vdb b 8 16
 do_or_freeze $BUSYBOX mknod -m 666 /dev/ttyS0 c 4 64
 do_or_freeze $BUSYBOX mknod -m 666 /dev/ttyS1 c 4 65
 
@@ -42,11 +42,11 @@ echo ok >&2
 do_or_freeze mkdir -p /etc /root /proc
 do_or_freeze mount -t procfs proc proc
 
-# Check if the device /dev/sdb is available and can be read
-if dd if=/dev/sdb of=/dev/null bs=512 count=1; then
+# Check if the device /dev/vdb is available and can be read
+if dd if=/dev/vdb of=/dev/null bs=512 count=1; then
     echo -n -e "Mounting the ext4 image... " >&2
     do_or_freeze mkdir -p /mnt1
-    do_or_freeze mount -t ext4 /dev/sdb /mnt1
+    do_or_freeze mount -t ext4 /dev/vdb /mnt1
     echo ok >&2
 fi