Browse Source

feat: impl vdso for all architectures and sigreturn for riscv64

greatbridf 11 tháng trước cách đây
mục cha
commit
c2eab5d866
33 tập tin đã thay đổi với 754 bổ sung334 xóa
  1. 16 1
      .vscode/launch.json
  2. 10 0
      crates/eonix_hal/eonix_hal_traits/src/trap.rs
  3. 33 18
      crates/eonix_hal/src/arch/riscv64/link.x
  4. 1 0
      crates/eonix_hal/src/arch/riscv64/memory.x
  5. 34 0
      crates/eonix_hal/src/arch/riscv64/trap/trap_context.rs
  6. 12 0
      crates/eonix_hal/src/arch/x86_64/link.x
  7. 1 0
      crates/eonix_hal/src/arch/x86_64/memory.x
  8. 6 5
      crates/eonix_hal/src/arch/x86_64/trap.rs
  9. 29 0
      crates/eonix_hal/src/arch/x86_64/trap/trap_context.rs
  10. 4 0
      crates/eonix_mm/src/page_table/page_table.rs
  11. 39 10
      crates/posix_types/src/ctypes.rs
  12. 13 1
      crates/posix_types/src/result.rs
  13. 5 1
      crates/posix_types/src/signal.rs
  14. 136 42
      crates/posix_types/src/signal/sig_action.rs
  15. 138 0
      crates/posix_types/src/signal/signal.rs
  16. 1 0
      crates/posix_types/src/syscall_no/riscv64.rs
  17. 41 0
      src/kernel/mem/mm_list.rs
  18. 2 1
      src/kernel/mem/mm_list/page_fault.rs
  19. 1 0
      src/kernel/syscall/file_rw.rs
  20. 42 17
      src/kernel/syscall/procops.rs
  21. 1 1
      src/kernel/task.rs
  22. 4 5
      src/kernel/task/clone.rs
  23. 14 9
      src/kernel/task/loader/elf.rs
  24. 10 9
      src/kernel/task/process.rs
  25. 2 1
      src/kernel/task/process_group.rs
  26. 2 1
      src/kernel/task/session.rs
  27. 42 16
      src/kernel/task/signal.rs
  28. 0 114
      src/kernel/task/signal/signal.rs
  29. 109 37
      src/kernel/task/signal/signal_action.rs
  30. 0 40
      src/kernel/task/signal/signal_mask.rs
  31. 2 1
      src/kernel/task/thread.rs
  32. 2 1
      src/kernel/terminal.rs
  33. 2 3
      src/kernel/vfs/file.rs

+ 16 - 1
.vscode/launch.json

@@ -19,6 +19,11 @@
                     "description": "Enable GDB pretty printing",
                     "ignoreFailures": true
                 },
+                {
+                    "text": "-exec set output-radix 16",
+                    "description": "Print addresses in hexadecimal",
+                    "ignoreFailures": true
+                },
                 // {
                 //     "text": "source ${workspaceFolder}/pretty-print.py",
                 //     "description": "Load GDB pretty printers",
@@ -47,6 +52,11 @@
                     "description": "Enable GDB pretty printing",
                     "ignoreFailures": true
                 },
+                {
+                    "text": "-exec set output-radix 16",
+                    "description": "Print addresses in hexadecimal",
+                    "ignoreFailures": true
+                },
                 // {
                 //     "text": "source ${workspaceFolder}/pretty-print.py",
                 //     "description": "Load GDB pretty printers",
@@ -74,7 +84,12 @@
                     "text": "-enable-pretty-printing",
                     "description": "Enable GDB pretty printing",
                     "ignoreFailures": true
-                }
+                },
+                {
+                    "text": "-exec set output-radix 16",
+                    "description": "Print addresses in hexadecimal",
+                    "ignoreFailures": true
+                },
             ]
         }
     ]

+ 10 - 0
crates/eonix_hal/eonix_hal_traits/src/trap.rs

@@ -1,5 +1,6 @@
 use crate::{context::RawTaskContext, fault::Fault};
 use core::marker::PhantomData;
+use eonix_mm::address::VAddr;
 
 /// A raw trap context.
 ///
@@ -24,6 +25,15 @@ pub trait RawTrapContext: Copy {
     fn set_user_mode(&mut self, user: bool);
 
     fn set_user_return_value(&mut self, retval: usize);
+
+    fn set_user_call_frame<E>(
+        &mut self,
+        pc: usize,
+        sp: Option<usize>,
+        ra: Option<usize>,
+        args: &[usize],
+        write_memory: impl Fn(VAddr, &[u8]) -> Result<(), E>,
+    ) -> Result<(), E>;
 }
 
 #[doc(notable_trait)]

+ 33 - 18
crates/eonix_hal/src/arch/riscv64/link.x

@@ -24,16 +24,31 @@ SECTIONS {
 INSERT AFTER .text;
 
 SECTIONS {
-    .rodata.fixups :
+    .percpu : ALIGN(16)
     {
+        __spercpu = .;
+
+        PERCPU_DATA_START = .;
+
         . = ALIGN(16);
-        FIX_START = .;
 
-        KEEP(*(.fix));
+        *(.percpu .percpu*);
 
-        FIX_END = .;
+        . = ALIGN(16);
+        __epercpu = .;
     } > REGION_RODATA AT> RAM
 
+    PERCPU_LENGTH = ABSOLUTE(__epercpu - __spercpu);
+
+    KIMAGE_PAGES = (__edata - _stext + 0x1000 - 1) / 0x1000;
+    KIMAGE_32K_COUNT = (KIMAGE_PAGES + 8 - 1) / 8;
+    __kernel_end = .;
+
+    BSS_LENGTH = ABSOLUTE(__ebss - __sbss);
+}
+INSERT AFTER .rodata;
+
+SECTIONS {
     .rodata.syscalls :
     {
         . = ALIGN(16);
@@ -51,26 +66,26 @@ SECTIONS {
 INSERT AFTER .rodata;
 
 SECTIONS {
-    .percpu : ALIGN(16)
+    .rodata.fixups :
     {
-        __spercpu = .;
-
-        PERCPU_DATA_START = .;
-
         . = ALIGN(16);
+        FIX_START = .;
 
-        *(.percpu .percpu*);
+        KEEP(*(.fix));
 
-        . = ALIGN(16);
-        __epercpu = .;
+        FIX_END = .;
     } > REGION_RODATA AT> RAM
+}
+INSERT AFTER .rodata;
 
-    PERCPU_LENGTH = ABSOLUTE(__epercpu - __spercpu);
+SECTIONS {
+    .vdso ALIGN(0x1000) : ALIGN(0x1000)
+    {
+        KEEP(*(.vdso .vdso.*));
 
-    KIMAGE_PAGES = (__edata - _stext + 0x1000 - 1) / 0x1000;
-    KIMAGE_32K_COUNT = (KIMAGE_PAGES + 8 - 1) / 8;
-    __kernel_end = .;
+        . = ALIGN(0x1000);
+    } > VDSO AT> RAM
 
-    BSS_LENGTH = ABSOLUTE(__ebss - __sbss);
+    VDSO_PADDR = LOADADDR(.vdso);
 }
-INSERT AFTER .rodata;
+INSERT AFTER .data;

+ 1 - 0
crates/eonix_hal/src/arch/riscv64/memory.x

@@ -3,6 +3,7 @@ ENTRY(_start)
 
 MEMORY {
     RAM    : org = 0x0000000080200000, len = 4M
+    VDSO   : org = 0x00007f0000000000, len = 4K
     KBSS   : org = 0xffffffff40000000, len = 2M
     KIMAGE : org = 0xffffffff80200000, len = 2M
 }

+ 34 - 0
crates/eonix_hal/src/arch/riscv64/trap/trap_context.rs

@@ -212,6 +212,40 @@ impl RawTrapContext for TrapContext {
     fn set_user_return_value(&mut self, retval: usize) {
         self.regs.a0 = retval as u64;
     }
+
+    fn set_user_call_frame<E>(
+        &mut self,
+        pc: usize,
+        sp: Option<usize>,
+        ra: Option<usize>,
+        args: &[usize],
+        _write_memory: impl Fn(VAddr, &[u8]) -> Result<(), E>,
+    ) -> Result<(), E> {
+        self.set_program_counter(pc);
+
+        if let Some(sp) = sp {
+            self.set_stack_pointer(sp);
+        }
+
+        if let Some(ra) = ra {
+            self.regs.ra = ra as u64;
+        }
+
+        let arg_regs = [
+            &mut self.regs.a0,
+            &mut self.regs.a1,
+            &mut self.regs.a2,
+            &mut self.regs.a3,
+            &mut self.regs.a4,
+            &mut self.regs.a5,
+        ];
+
+        for (&arg, reg) in args.iter().zip(arg_regs.into_iter()) {
+            *reg = arg as u64;
+        }
+
+        Ok(())
+    }
 }
 
 impl TrapContext {

+ 12 - 0
crates/eonix_hal/src/arch/x86_64/link.x

@@ -34,6 +34,18 @@ SECTIONS {
     } > LOWMEM AT> LOWMEM
 }
 
+SECTIONS {
+    .vdso ALIGN(0x1000) : ALIGN(0x1000)
+    {
+        KEEP(*(.vdso .vdso.*));
+
+        . = ALIGN(0x1000);
+    } > VDSO AT> REGION_TEXT
+
+    VDSO_PADDR = LOADADDR(.vdso);
+}
+INSERT AFTER .text;
+
 SECTIONS {
     .text.syscall_fns :
     {

+ 1 - 0
crates/eonix_hal/src/arch/x86_64/memory.x

@@ -1,5 +1,6 @@
 MEMORY {
     LOWMEM : org = 0x0000000000000000, len = 1M
+    VDSO   : org = 0x00007f0000000000, len = 4K
     KBSS   : org = 0xffffffffc0200000, len = 2M
     KIMAGE : org = 0xffffffffffc00000, len = 2M
 }

+ 6 - 5
crates/eonix_hal/src/arch/x86_64/trap.rs

@@ -331,16 +331,17 @@ unsafe extern "C" fn captured_trap_return(trap_context: usize) -> ! {
 impl TrapReturn for TrapContext {
     type TaskContext = TaskContext;
 
-    unsafe fn trap_return(&mut self, task_ctx: &mut Self::TaskContext) {
+    unsafe fn trap_return(&mut self) {
         let irq_states = disable_irqs_save();
         let old_handler = TRAP_HANDLER.swap(captured_trap_handler);
 
-        task_ctx.set_program_counter(captured_trap_return as _);
-        task_ctx.set_stack_pointer(&raw mut *self as usize);
-        task_ctx.set_interrupt_enabled(false);
+        let mut to_ctx = TaskContext::new();
+        to_ctx.set_program_counter(captured_trap_return as _);
+        to_ctx.set_stack_pointer(&raw mut *self as usize);
+        to_ctx.set_interrupt_enabled(false);
 
         unsafe {
-            TaskContext::switch(CAPTURER_CONTEXT.as_mut(), &mut *task_ctx);
+            TaskContext::switch(CAPTURER_CONTEXT.as_mut(), &mut to_ctx);
         }
 
         TRAP_HANDLER.set(old_handler);

+ 29 - 0
crates/eonix_hal/src/arch/x86_64/trap/trap_context.rs

@@ -142,4 +142,33 @@ impl RawTrapContext for TrapContext {
     fn set_user_return_value(&mut self, retval: usize) {
         self.rax = retval as u64;
     }
+
+    fn set_user_call_frame<E>(
+        &mut self,
+        pc: usize,
+        sp: Option<usize>,
+        ra: Option<usize>,
+        args: &[usize],
+        write_memory: impl Fn(VAddr, &[u8]) -> Result<(), E>,
+    ) -> Result<(), E> {
+        self.set_program_counter(pc);
+
+        let mut sp = sp.unwrap_or_else(|| self.get_stack_pointer());
+
+        let arg_size = args.len() * 4;
+
+        sp -= arg_size;
+        sp &= !0xf; // Align to 16 bytes
+        for (idx, arg) in args.iter().enumerate() {
+            write_memory(VAddr::from(sp + idx * 8), &arg.to_ne_bytes())?;
+        }
+
+        if let Some(ra) = ra {
+            sp -= 4; // Space for return address
+            write_memory(VAddr::from(sp), &ra.to_ne_bytes())?;
+        }
+
+        self.set_stack_pointer(sp);
+        Ok(())
+    }
 }

+ 4 - 0
crates/eonix_mm/src/page_table/page_table.rs

@@ -176,6 +176,10 @@ where
 
     fn drop_page_table_recursive(page_table: &Page<A>, levels: &[PageTableLevel]) {
         let [level, remaining_levels @ ..] = levels else { return };
+        if remaining_levels.is_empty() {
+            // We reached the last level, no need to go deeper.
+            return;
+        }
 
         let alloc = page_table.allocator();
 

+ 39 - 10
crates/posix_types/src/ctypes.rs

@@ -1,24 +1,53 @@
+use crate::result::PosixError;
+
 #[cfg(target_arch = "x86_64")]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct PtrT(u32);
+pub(crate) type ArchPtrType = u32;
 
 #[cfg(not(target_arch = "x86_64"))]
+pub(crate) type ArchPtrType = u64;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PtrT(pub(crate) ArchPtrType);
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct PtrT(u64);
+pub struct Long(pub(crate) ArchPtrType);
 
 impl PtrT {
-    pub fn new(ptr: usize) -> Self {
-        PtrT(
-            ptr.try_into()
-                .expect("Pointer truncated when converting to ptr_t"),
-        )
+    pub fn new(ptr: usize) -> Result<Self, PosixError> {
+        ptr.try_into().map(Self).map_err(|_| PosixError::EFAULT)
     }
 
-    pub fn addr(self) -> usize {
+    pub const fn new_val(ptr: ArchPtrType) -> Self {
+        Self(ptr as ArchPtrType)
+    }
+
+    pub const fn null() -> Self {
+        Self(0)
+    }
+
+    pub const fn addr(self) -> usize {
         self.0 as usize
     }
 
-    pub fn is_null(self) -> bool {
+    pub const fn is_null(self) -> bool {
         self.0 == 0
     }
 }
+
+impl Long {
+    pub fn new(value: usize) -> Result<Self, PosixError> {
+        value.try_into().map(Self).map_err(|_| PosixError::EINVAL)
+    }
+
+    pub const fn new_val(value: ArchPtrType) -> Self {
+        Self(value as ArchPtrType)
+    }
+
+    pub const fn zero() -> Self {
+        Self(0)
+    }
+
+    pub const fn get(self) -> usize {
+        self.0 as usize
+    }
+}

+ 13 - 1
crates/posix_types/src/result.rs

@@ -1 +1,13 @@
-pub enum PosixError {}
+pub enum PosixError {
+    EFAULT = 14,
+    EINVAL = 22,
+}
+
+impl From<PosixError> for u32 {
+    fn from(error: PosixError) -> Self {
+        match error {
+            PosixError::EFAULT => 14,
+            PosixError::EINVAL => 22,
+        }
+    }
+}

+ 5 - 1
crates/posix_types/src/signal.rs

@@ -1,5 +1,9 @@
 mod sig_action;
 mod siginfo;
+mod signal;
 
-pub use sig_action::{SigAction, TryFromSigAction};
+pub use sig_action::{
+    SigAction, SigActionFlags, SigActionHandler, SigActionRestorer, SigSet, TryFromSigAction,
+};
 pub use siginfo::SigInfo;
+pub use signal::Signal;

+ 136 - 42
crates/posix_types/src/signal/sig_action.rs

@@ -1,10 +1,43 @@
-#[repr(C, packed)]
+use super::Signal;
+use crate::ctypes::PtrT;
+use bitflags::bitflags;
+
+bitflags! {
+    #[derive(Debug, Clone, Copy)]
+    pub struct SigActionFlags: usize {
+        const SA_SIGINFO = 0x00000004;   // Use sa_sigaction instead of sa_handler.
+        const SA_RESTORER = 0x04000000; // Use sa_restorer to restore the context after the handler.
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct SigActionHandler(PtrT);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct SigActionRestorer(PtrT);
+
+#[cfg_attr(target_arch = "x86_64", repr(align(4)))]
+#[cfg_attr(not(target_arch = "x86_64"), repr(align(8)))]
+#[derive(Debug, Clone, Copy, Default)]
+pub struct SigSet(u64);
+
+#[cfg(target_arch = "x86_64")]
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct SigAction {
+    sa_handler: SigActionHandler,
+    sa_flags: SigActionFlags,
+    sa_restorer: SigActionRestorer,
+    sa_mask: SigSet,
+}
+
+#[cfg(not(target_arch = "x86_64"))]
+#[repr(C)]
 #[derive(Debug, Clone, Copy)]
 pub struct SigAction {
-    sa_handler: u32,
-    sa_flags: u32,
-    sa_restorer: u32,
-    sa_mask: u64,
+    sa_handler: SigActionHandler,
+    sa_flags: SigActionFlags,
+    sa_mask: SigSet,
 }
 
 pub trait TryFromSigAction: Sized {
@@ -15,61 +48,124 @@ pub trait TryFromSigAction: Sized {
     fn new() -> Self;
 
     fn set_siginfo(self) -> Result<Self, Self::Error>;
-    fn handler(self, handler: usize) -> Result<Self, Self::Error>;
-    fn restorer(self, restorer: usize) -> Result<Self, Self::Error>;
-    fn mask(self, mask: u64) -> Result<Self, Self::Error>;
+    fn handler(self, handler: SigActionHandler) -> Self;
+    fn restorer(self, restorer: SigActionRestorer) -> Self;
+    fn mask(self, mask: SigSet) -> Self;
+}
+
+impl SigActionHandler {
+    const DEFAULT: Self = Self(PtrT::new_val(0));
+    const IGNORE: Self = Self(PtrT::new_val(1));
+
+    pub const fn new(handler: PtrT) -> Self {
+        Self(handler)
+    }
+
+    pub const fn null() -> Self {
+        Self(PtrT::null())
+    }
+
+    pub const fn addr(self) -> PtrT {
+        self.0
+    }
+}
+
+impl SigActionRestorer {
+    pub const fn new(restorer: PtrT) -> Self {
+        Self(restorer)
+    }
+
+    pub const fn null() -> Self {
+        Self(PtrT::null())
+    }
+
+    pub const fn addr(self) -> PtrT {
+        self.0
+    }
 }
 
-const SIG_DFL: u32 = 0;
-const SIG_IGN: u32 = 1;
+impl SigSet {
+    pub const fn empty() -> Self {
+        Self(0)
+    }
+
+    pub fn mask(&mut self, mask: Self) {
+        self.0 |= mask.0;
+    }
+
+    pub fn unmask(&mut self, mask: Self) {
+        self.0 &= !mask.0;
+    }
+
+    pub fn include(&self, signal: Signal) -> bool {
+        let signal_mask = Self::from(signal);
+        (self.0 & signal_mask.0) != 0
+    }
+}
 
-const SA_SIGINFO: u32 = 4;
-const SA_RESTORER: u32 = 0x04000000;
+impl From<Signal> for SigSet {
+    fn from(signal: Signal) -> Self {
+        let mut sigset = Self::empty();
+        sigset.mask(Self(1 << (signal.into_raw() - 1)));
+        sigset
+    }
+}
 
 impl SigAction {
     pub const fn default() -> Self {
         Self {
-            sa_handler: SIG_DFL,
-            sa_flags: 0,
-            sa_restorer: 0,
-            sa_mask: 0,
+            sa_handler: SigActionHandler::DEFAULT,
+            sa_flags: SigActionFlags::empty(),
+            #[cfg(target_arch = "x86_64")]
+            sa_restorer: SigActionRestorer::null(),
+            sa_mask: SigSet::empty(),
         }
     }
 
     pub const fn ignore() -> Self {
         Self {
-            sa_handler: SIG_IGN,
-            sa_flags: 0,
-            sa_restorer: 0,
-            sa_mask: 0,
+            sa_handler: SigActionHandler::IGNORE,
+            sa_flags: SigActionFlags::empty(),
+            #[cfg(target_arch = "x86_64")]
+            sa_restorer: SigActionRestorer::null(),
+            sa_mask: SigSet::empty(),
         }
     }
 
     pub const fn new() -> Self {
         Self {
-            sa_handler: 0,
-            sa_flags: 0,
-            sa_restorer: 0,
-            sa_mask: 0,
+            sa_handler: SigActionHandler::null(),
+            sa_flags: SigActionFlags::empty(),
+            #[cfg(target_arch = "x86_64")]
+            sa_restorer: SigActionRestorer::null(),
+            sa_mask: SigSet::empty(),
         }
     }
 
-    pub const fn handler(self, handler: usize) -> Self {
+    pub fn handler(self, handler: SigActionHandler) -> Self {
         Self {
-            sa_handler: handler as u32,
+            sa_handler: handler,
             ..self
         }
     }
 
-    pub const fn restorer(self, restorer: usize) -> Self {
+    #[cfg(not(target_arch = "x86_64"))]
+    pub fn restorer(self, _restorer: SigActionRestorer) -> Self {
+        // On non-x86_64 architectures, the restorer does not exist.
+        self
+    }
+
+    #[cfg(target_arch = "x86_64")]
+    pub fn restorer(mut self, restorer: SigActionRestorer) -> Self {
+        self.sa_flags.insert(SigActionFlags::SA_RESTORER);
+
         Self {
-            sa_restorer: restorer as u32,
-            sa_flags: self.sa_flags | SA_RESTORER,
+            sa_restorer: restorer,
             ..self
         }
     }
 
-    pub const fn mask(self, mask: u64) -> Self {
+    pub const fn mask(self, mask: SigSet) -> Self {
         Self {
             sa_mask: mask,
             ..self
@@ -81,26 +177,24 @@ impl SigAction {
         T: TryFromSigAction,
     {
         match self.sa_handler {
-            SIG_DFL => Ok(T::default()),
-            SIG_IGN => Ok(T::ignore()),
+            SigActionHandler::DEFAULT => Ok(T::default()),
+            SigActionHandler::IGNORE => Ok(T::ignore()),
             _ => {
                 let mut action = T::new();
-                if self.sa_flags & SA_SIGINFO != 0 {
+                if self.sa_flags.contains(SigActionFlags::SA_SIGINFO) {
                     action = action.set_siginfo()?;
                 }
 
-                action = action.handler(self.sa_handler as usize)?;
-                action = action.restorer(self.sa_restorer as usize)?;
-                action = action.mask(self.sa_mask)?;
+                action = action.handler(self.sa_handler);
+                action = action.mask(self.sa_mask);
+
+                #[cfg(target_arch = "x86_64")]
+                {
+                    action = action.restorer(self.sa_restorer);
+                }
 
                 Ok(action)
             }
         }
     }
 }
-
-impl Default for SigAction {
-    fn default() -> Self {
-        Self::default()
-    }
-}

+ 138 - 0
crates/posix_types/src/signal/signal.rs

@@ -0,0 +1,138 @@
+use crate::result::PosixError;
+use core::fmt;
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Signal(u32);
+
+impl Signal {
+    pub const SIGHUP: Signal = Signal(1);
+    pub const SIGINT: Signal = Signal(2);
+    pub const SIGQUIT: Signal = Signal(3);
+    pub const SIGILL: Signal = Signal(4);
+    pub const SIGTRAP: Signal = Signal(5);
+    pub const SIGABRT: Signal = Signal(6);
+    pub const SIGIOT: Signal = Signal(6);
+    pub const SIGBUS: Signal = Signal(7);
+    pub const SIGFPE: Signal = Signal(8);
+    pub const SIGKILL: Signal = Signal(9);
+    pub const SIGUSR1: Signal = Signal(10);
+    pub const SIGSEGV: Signal = Signal(11);
+    pub const SIGUSR2: Signal = Signal(12);
+    pub const SIGPIPE: Signal = Signal(13);
+    pub const SIGALRM: Signal = Signal(14);
+    pub const SIGTERM: Signal = Signal(15);
+    pub const SIGSTKFLT: Signal = Signal(16);
+    pub const SIGCHLD: Signal = Signal(17);
+    pub const SIGCONT: Signal = Signal(18);
+    pub const SIGSTOP: Signal = Signal(19);
+    pub const SIGTSTP: Signal = Signal(20);
+    pub const SIGTTIN: Signal = Signal(21);
+    pub const SIGTTOU: Signal = Signal(22);
+    pub const SIGURG: Signal = Signal(23);
+    pub const SIGXCPU: Signal = Signal(24);
+    pub const SIGXFSZ: Signal = Signal(25);
+    pub const SIGVTALRM: Signal = Signal(26);
+    pub const SIGPROF: Signal = Signal(27);
+    pub const SIGWINCH: Signal = Signal(28);
+    pub const SIGIO: Signal = Signal(29);
+    pub const SIGPOLL: Signal = Signal(29);
+    pub const SIGPWR: Signal = Signal(30);
+    pub const SIGSYS: Signal = Signal(31);
+
+    pub const SIGNUM_MIN: u32 = 1;
+    pub const SIGNUM_MAX: u32 = 64;
+
+    pub fn into_raw(self) -> u32 {
+        self.0
+    }
+
+    pub fn try_from_raw(signo: u32) -> Result<Self, PosixError> {
+        match signo {
+            ..Self::SIGNUM_MAX => Ok(Signal(signo)),
+            _ => Err(PosixError::EINVAL),
+        }
+    }
+}
+
+impl fmt::Debug for Signal {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            &Signal(0) => write!(f, "Signal::EMPTY"),
+            &Signal::SIGHUP => write!(f, "SIGHUP"),
+            &Signal::SIGINT => write!(f, "SIGINT"),
+            &Signal::SIGQUIT => write!(f, "SIGQUIT"),
+            &Signal::SIGILL => write!(f, "SIGILL"),
+            &Signal::SIGTRAP => write!(f, "SIGTRAP"),
+            &Signal::SIGABRT => write!(f, "SIGABRT"),
+            &Signal::SIGBUS => write!(f, "SIGBUS"),
+            &Signal::SIGFPE => write!(f, "SIGFPE"),
+            &Signal::SIGKILL => write!(f, "SIGKILL"),
+            &Signal::SIGUSR1 => write!(f, "SIGUSR1"),
+            &Signal::SIGSEGV => write!(f, "SIGSEGV"),
+            &Signal::SIGUSR2 => write!(f, "SIGUSR2"),
+            &Signal::SIGPIPE => write!(f, "SIGPIPE"),
+            &Signal::SIGALRM => write!(f, "SIGALRM"),
+            &Signal::SIGTERM => write!(f, "SIGTERM"),
+            &Signal::SIGSTKFLT => write!(f, "SIGSTKFLT"),
+            &Signal::SIGCHLD => write!(f, "SIGCHLD"),
+            &Signal::SIGCONT => write!(f, "SIGCONT"),
+            &Signal::SIGSTOP => write!(f, "SIGSTOP"),
+            &Signal::SIGTSTP => write!(f, "SIGTSTP"),
+            &Signal::SIGTTIN => write!(f, "SIGTTIN"),
+            &Signal::SIGTTOU => write!(f, "SIGTTOU"),
+            &Signal::SIGURG => write!(f, "SIGURG"),
+            &Signal::SIGXCPU => write!(f, "SIGXCPU"),
+            &Signal::SIGXFSZ => write!(f, "SIGXFSZ"),
+            &Signal::SIGVTALRM => write!(f, "SIGVTALRM"),
+            &Signal::SIGPROF => write!(f, "SIGPROF"),
+            &Signal::SIGWINCH => write!(f, "SIGWINCH"),
+            &Signal::SIGIO => write!(f, "SIGNOIO/SIGPOLL"),
+            &Signal::SIGPWR => write!(f, "SIGHUPWR"),
+            &Signal::SIGSYS => write!(f, "SIGSYS"),
+            &Signal(signo @ ..Signal::SIGNUM_MAX) => write!(f, "SIGUSER{}", signo),
+            &Signal(signo) => write!(f, "Signal::UNKNOWN({})", signo),
+        }
+    }
+}
+
+#[macro_export]
+macro_rules! SIGNAL_IGNORE {
+    () => {
+        $crate::signal::Signal::SIGCHLD
+            | $crate::signal::Signal::SIGURG
+            | $crate::signal::Signal::SIGWINCH
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_NOW {
+    () => {
+        $crate::signal::Signal::SIGKILL | $crate::signal::Signal::SIGSTOP
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_COREDUMP {
+    () => {
+        $crate::signal::Signal::SIGQUIT
+            | $crate::signal::Signal::SIGILL
+            | $crate::signal::Signal::SIGABRT
+            | $crate::signal::Signal::SIGFPE
+            | $crate::signal::Signal::SIGSEGV
+            | $crate::signal::Signal::SIGBUS
+            | $crate::signal::Signal::SIGTRAP
+            | $crate::signal::Signal::SIGSYS
+            | $crate::signal::Signal::SIGXCPU
+            | $crate::signal::Signal::SIGXFSZ
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_STOP {
+    () => {
+        $crate::signal::Signal::SIGSTOP
+            | $crate::signal::Signal::SIGTSTP
+            | $crate::signal::Signal::SIGTTIN
+            | $crate::signal::Signal::SIGTTOU
+    };
+}

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

@@ -140,6 +140,7 @@ pub const SYS_RT_SIGPROCMASK: usize = 135;
 pub const SYS_RT_SIGPENDING: usize = 136;
 pub const SYS_RT_SIGTIMEDWAIT_TIME32: usize = 137;
 pub const SYS_RT_SIGQUEUEINFO: usize = 138;
+pub const SYS_RT_SIGRETURN: usize = 139;
 pub const SYS_SETPRIORITY: usize = 140;
 pub const SYS_GETPRIORITY: usize = 141;
 pub const SYS_REBOOT: usize = 142;

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

@@ -460,6 +460,47 @@ impl MMList {
         Ok(())
     }
 
+    pub fn map_vdso(&self) -> KResult<()> {
+        unsafe extern "C" {
+            fn VDSO_PADDR();
+        }
+        static VDSO_PADDR_VALUE: &'static unsafe extern "C" fn() =
+            &(VDSO_PADDR as unsafe extern "C" fn());
+
+        let vdso_paddr = unsafe {
+            // SAFETY: To prevent the compiler from optimizing this into `la` instructions
+            //         and causing a linking error.
+            (VDSO_PADDR_VALUE as *const _ as *const usize).read_volatile()
+        };
+
+        let vdso_pfn = PFN::from(PAddr::from(vdso_paddr));
+
+        const VDSO_START: VAddr = VAddr::from(0x7f00_0000_0000);
+        const VDSO_SIZE: usize = 0x1000;
+
+        let inner = self.inner.borrow();
+        let inner = Task::block_on(inner.lock());
+
+        let mut pte_iter = inner
+            .page_table
+            .iter_user(VRange::from(VDSO_START).grow(VDSO_SIZE));
+
+        let pte = pte_iter.next().expect("There should be at least one PTE");
+        pte.set(
+            vdso_pfn,
+            (PageAttribute::PRESENT
+                | PageAttribute::READ
+                | PageAttribute::EXECUTE
+                | PageAttribute::USER
+                | PageAttribute::ACCESSED)
+                .into(),
+        );
+
+        assert!(pte_iter.next().is_none(), "There should be only one PTE");
+
+        Ok(())
+    }
+
     pub fn mmap_hint(
         &self,
         hint: VAddr,

+ 2 - 1
src/kernel/mem/mm_list/page_fault.rs

@@ -1,10 +1,11 @@
 use super::{MMList, VAddr};
-use crate::kernel::task::{Signal, 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};
 use eonix_mm::paging::PAGE_SIZE;
 use eonix_runtime::task::Task;
+use posix_types::signal::Signal;
 
 #[repr(C)]
 struct FixEntry {

+ 1 - 0
src/kernel/syscall/file_rw.rs

@@ -291,6 +291,7 @@ fn llseek(fd: FD, offset_high: u32, offset_low: u32, result: *mut u64, whence: u
     result.copy(&new_offset)?.ok_or(EFAULT)
 }
 
+// TODO!!!: This type should differ based on architecture.
 #[repr(C)]
 #[derive(Default, Clone, Copy)]
 struct IoVec32 {

+ 42 - 17
src/kernel/syscall/procops.rs

@@ -7,15 +7,14 @@ use crate::kernel::constants::{
 };
 use crate::kernel::mem::PageBuffer;
 use crate::kernel::task::{
-    do_clone, futex_wait, futex_wake, FutexFlags, FutexOp, ProcessList, ProgramLoader, Signal,
-    SignalAction, SignalMask, Thread, WaitObject, WaitType,
+    do_clone, futex_wait, futex_wake, FutexFlags, FutexOp, ProcessList, ProgramLoader,
+    SignalAction, Thread, WaitObject, WaitType,
 };
 use crate::kernel::task::{parse_futexop, CloneArgs};
 use crate::kernel::user::dataflow::{CheckedUserPointer, UserString};
 use crate::kernel::user::{UserPointer, UserPointerMut};
 use crate::kernel::vfs::{self, dentry::Dentry};
 use crate::path::Path;
-use crate::SIGNAL_NOW;
 use crate::{kernel::user::dataflow::UserBuffer, prelude::*};
 use alloc::borrow::ToOwned;
 use alloc::ffi::CString;
@@ -28,8 +27,8 @@ use eonix_runtime::task::Task;
 use eonix_sync::AsProof as _;
 use posix_types::constants::{P_ALL, P_PID};
 use posix_types::ctypes::PtrT;
-use posix_types::signal::{SigAction, SigInfo};
-use posix_types::syscall_no::*;
+use posix_types::signal::{SigAction, SigInfo, SigSet, Signal};
+use posix_types::{syscall_no::*, SIGNAL_NOW};
 
 #[repr(C)]
 #[derive(Debug, Clone, Copy)]
@@ -132,7 +131,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<()> {
+fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<SyscallNoReturn> {
     let exec = UserString::new(exec)?;
     let argv = get_strings(UserPointer::new(argv)?)?;
     let envp = get_strings(UserPointer::new(envp)?)?;
@@ -161,7 +160,7 @@ fn execve(exec: *const u8, argv: *const PtrT, envp: *const PtrT) -> KResult<()>
         let mut trap_ctx = thread.trap_ctx.borrow();
         trap_ctx.set_program_counter(load_info.entry_ip.addr());
         trap_ctx.set_stack_pointer(load_info.sp.addr());
-        Ok(())
+        Ok(SyscallNoReturn)
     } else {
         // We can't hold any ownership when we call `kill_current`.
         // ProcessList::kill_current(Signal::SIGSEGV);
@@ -232,7 +231,7 @@ fn do_waitid(
             let mut siginfo = SigInfo::default();
             siginfo.si_pid = wait_object.pid;
             siginfo.si_uid = 0; // All users are root for now.
-            siginfo.si_signo = u32::from(Signal::SIGCHLD);
+            siginfo.si_signo = Signal::SIGCHLD.into_raw();
             siginfo.si_status = status;
             siginfo.si_code = code;
 
@@ -488,17 +487,17 @@ fn kill(pid: i32, sig: u32) -> KResult<()> {
         0 => thread
             .process
             .pgroup(procs.prove())
-            .raise(Signal::try_from(sig)?, procs.prove()),
+            .raise(Signal::try_from_raw(sig)?, procs.prove()),
         // Send signal to the process with the specified pid.
         1.. => procs
             .try_find_process(pid as u32)
             .ok_or(ESRCH)?
-            .raise(Signal::try_from(sig)?, procs.prove()),
+            .raise(Signal::try_from_raw(sig)?, procs.prove()),
         // Send signal to the process group with the specified pgid equals to `-pid`.
         ..-1 => procs
             .try_find_pgroup((-pid) as u32)
             .ok_or(ESRCH)?
-            .raise(Signal::try_from(sig)?, procs.prove()),
+            .raise(Signal::try_from_raw(sig)?, procs.prove()),
     }
 
     Ok(())
@@ -509,23 +508,28 @@ fn tkill(tid: u32, sig: u32) -> KResult<()> {
     Task::block_on(ProcessList::get().read())
         .try_find_thread(tid)
         .ok_or(ESRCH)?
-        .raise(Signal::try_from(sig)?);
+        .raise(Signal::try_from_raw(sig)?);
     Ok(())
 }
 
 #[eonix_macros::define_syscall(SYS_RT_SIGPROCMASK)]
-fn rt_sigprocmask(how: u32, set: *mut u64, oldset: *mut u64, sigsetsize: usize) -> KResult<()> {
-    if sigsetsize != size_of::<u64>() {
+fn rt_sigprocmask(
+    how: u32,
+    set: *mut SigSet,
+    oldset: *mut SigSet,
+    sigsetsize: usize,
+) -> KResult<()> {
+    if sigsetsize != size_of::<SigSet>() {
         return Err(EINVAL);
     }
 
-    let old_mask = u64::from(thread.signal_list.get_mask());
+    let old_mask = thread.signal_list.get_mask();
     if !oldset.is_null() {
         UserPointerMut::new(oldset)?.write(old_mask)?;
     }
 
     let new_mask = if !set.is_null() {
-        SignalMask::from(UserPointer::new(set)?.read()?)
+        UserPointer::new(set)?.read()?
     } else {
         return Ok(());
     };
@@ -547,7 +551,7 @@ fn rt_sigaction(
     oldact: *mut SigAction,
     sigsetsize: usize,
 ) -> KResult<()> {
-    let signal = Signal::try_from(signum)?;
+    let signal = Signal::try_from_raw(signum)?;
     if sigsetsize != size_of::<u64>() {
         return Err(EINVAL);
     }
@@ -734,6 +738,26 @@ fn futex(
     }
 }
 
+#[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
+            );
+            Task::block_on(thread.force_kill(Signal::SIGSEGV));
+        })?;
+
+    Ok(SyscallNoReturn)
+}
+
 #[cfg(target_arch = "x86_64")]
 #[eonix_macros::define_syscall(SYS_SIGRETURN)]
 fn sigreturn() -> KResult<SyscallNoReturn> {
@@ -742,6 +766,7 @@ fn sigreturn() -> KResult<SyscallNoReturn> {
         .restore(
             &mut thread.trap_ctx.borrow(),
             &mut thread.fpu_state.borrow(),
+            true,
         )
         .inspect_err(|err| {
             println_warn!(

+ 1 - 1
src/kernel/task.rs

@@ -17,5 +17,5 @@ pub use process::{alloc_pid, Process, ProcessBuilder, WaitObject, WaitType};
 pub use process_group::ProcessGroup;
 pub use process_list::ProcessList;
 pub use session::Session;
-pub use signal::{Signal, SignalAction, SignalMask};
+pub use signal::SignalAction;
 pub use thread::{new_thread_runnable, Thread, ThreadBuilder};

+ 4 - 5
src/kernel/task/clone.rs

@@ -5,7 +5,7 @@ use crate::{
             alloc_pid, new_thread_runnable, KernelStack, ProcessBuilder, ProcessList, Thread,
             ThreadBuilder,
         },
-        user::{dataflow::CheckedUserPointer, UserPointerMut},
+        user::UserPointerMut,
     },
     KResult,
 };
@@ -14,8 +14,7 @@ use core::num::NonZero;
 use eonix_hal::processor::UserTLS;
 use eonix_runtime::{scheduler::Scheduler, task::Task};
 use eonix_sync::AsProof;
-
-use crate::kernel::task::Signal;
+use posix_types::signal::Signal;
 
 bitflags! {
     #[derive(Debug, Default)]
@@ -71,7 +70,7 @@ impl CloneArgs {
         let clone_flags = CloneFlags::from_bits_truncate(flags & !Self::MASK);
         let exit_signal = flags & Self::MASK;
         let exit_signal = if exit_signal != 0 {
-            Some(Signal::try_from(exit_signal as u32)?)
+            Some(Signal::try_from_raw(exit_signal as u32)?)
         } else {
             None
         };
@@ -153,7 +152,7 @@ pub fn do_clone(thread: &Thread, clone_args: CloneArgs) -> KResult<u32> {
         let current_pgroup = current_process.pgroup(procs.prove()).clone();
         let current_session = current_process.session(procs.prove()).clone();
 
-        let (new_thread, new_process) = ProcessBuilder::new()
+        let (new_thread, _) = ProcessBuilder::new()
             .clone_from(current_process, &clone_args)
             .pid(new_pid)
             .pgroup(current_pgroup)

+ 14 - 9
src/kernel/task/loader/elf.rs

@@ -1,5 +1,4 @@
 use super::{LoadInfo, ELF_MAGIC};
-
 use crate::io::UninitBuffer;
 use crate::kernel::task::loader::aux_vec::{AuxKey, AuxVec};
 use crate::path::Path;
@@ -19,7 +18,6 @@ use eonix_mm::{
     address::{Addr, AddrOps as _, VAddr},
     paging::PAGE_SIZE,
 };
-
 use xmas_elf::{
     header::{self, Class, HeaderPt1, Machine_},
     program::{self, ProgramHeader32, ProgramHeader64},
@@ -52,7 +50,7 @@ struct ElfHeader<P> {
     pt2: HeaderPt2<P>,
 }
 
-trait ProgramHeader {
+pub trait ProgramHeader {
     fn offset(&self) -> usize;
     fn file_size(&self) -> usize;
     fn virtual_addr(&self) -> usize;
@@ -99,7 +97,7 @@ struct LdsoLoadInfo {
     entry_ip: VAddr,
 }
 
-trait ElfAddr {
+pub trait ElfAddr {
     type Integer;
 
     fn from_usize(val: usize) -> Self;
@@ -125,7 +123,7 @@ macro_rules! impl_elf_addr {
 impl_elf_addr!(u32);
 impl_elf_addr!(u64);
 
-trait ElfArch {
+pub trait ElfArch {
     type Ea: ElfAddr + Clone + Copy;
     type Ph: ProgramHeader + Clone + Copy + Default;
 
@@ -134,11 +132,11 @@ trait ElfArch {
     const STACK_BASE_ADDR: usize;
 }
 
-struct ElfArch32;
+pub struct ElfArch32;
 
-struct ElfArch64;
+pub struct ElfArch64;
 
-struct Elf<E: ElfArch> {
+pub struct Elf<E: ElfArch> {
     file: Arc<Dentry>,
     elf_header: ElfHeader<E::Ea>,
     program_headers: Vec<E::Ph>,
@@ -223,9 +221,12 @@ impl<E: ElfArch> Elf<E> {
         // Load Segments
         let (elf_base, data_segment_end) = self.load_segments(&mm_list)?;
 
-        // Load ldso(if have)
+        // Load ldso (if any)
         let ldso_load_info = self.load_ldso(&mm_list)?;
 
+        // Load vdso
+        self.load_vdso(&mm_list)?;
+
         // Heap
         mm_list.register_break(data_segment_end + 0x10000);
 
@@ -399,6 +400,10 @@ impl<E: ElfArch> Elf<E> {
         Ok(None)
     }
 
+    fn load_vdso(&self, mm_list: &MMList) -> KResult<()> {
+        mm_list.map_vdso()
+    }
+
     fn ldso_path(&self) -> KResult<Option<String>> {
         for program_header in &self.program_headers {
             let type_ = program_header.type_().map_err(|_| ENOEXEC)?;

+ 10 - 9
src/kernel/task/process.rs

@@ -1,6 +1,6 @@
 use super::{
     process_group::ProcessGroupBuilder, signal::RaiseResult, thread::ThreadBuilder, ProcessGroup,
-    ProcessList, Session, Signal, Thread,
+    ProcessList, Session, Thread,
 };
 use crate::kernel::constants::{ECHILD, EINTR, EPERM, ESRCH};
 use crate::kernel::task::{CloneArgs, CloneFlags};
@@ -9,7 +9,6 @@ use crate::{
     prelude::*,
     rcu::{rcu_sync, RCUPointer, RCUReadGuard},
     sync::CondVar,
-    SIGNAL_COREDUMP,
 };
 use alloc::{
     collections::{btree_map::BTreeMap, vec_deque::VecDeque},
@@ -23,6 +22,8 @@ use eonix_sync::{
 };
 use pointers::BorrowedArc;
 use posix_types::constants::{CLD_CONTINUED, CLD_DUMPED, CLD_EXITED, CLD_KILLED, CLD_STOPPED};
+use posix_types::signal::Signal;
+use posix_types::SIGNAL_COREDUMP;
 
 pub struct ProcessBuilder {
     mm_list: Option<MMList>,
@@ -118,9 +119,9 @@ impl WaitType {
     pub fn to_wstatus(self) -> u32 {
         match self {
             WaitType::Exited(status) => (status & 0xff) << 8,
-            WaitType::Signaled(signal @ SIGNAL_COREDUMP!()) => u32::from(signal) | 0x80,
-            WaitType::Signaled(signal) => u32::from(signal),
-            WaitType::Stopped(signal) => 0x7f | (u32::from(signal) << 8),
+            WaitType::Signaled(signal @ SIGNAL_COREDUMP!()) => signal.into_raw() | 0x80,
+            WaitType::Signaled(signal) => signal.into_raw(),
+            WaitType::Stopped(signal) => 0x7f | (signal.into_raw() << 8),
             WaitType::Continued => 0xffff,
         }
     }
@@ -129,10 +130,10 @@ impl WaitType {
         // TODO: CLD_TRAPPED
         match self {
             WaitType::Exited(status) => (status, CLD_EXITED),
-            WaitType::Signaled(signal @ SIGNAL_COREDUMP!()) => (u32::from(signal), CLD_DUMPED),
-            WaitType::Signaled(signal) => (u32::from(signal), CLD_KILLED),
-            WaitType::Stopped(signal) => (u32::from(signal), CLD_STOPPED),
-            WaitType::Continued => (u32::from(Signal::SIGCONT), CLD_CONTINUED),
+            WaitType::Signaled(signal @ SIGNAL_COREDUMP!()) => (signal.into_raw(), CLD_DUMPED),
+            WaitType::Signaled(signal) => (signal.into_raw(), CLD_KILLED),
+            WaitType::Stopped(signal) => (signal.into_raw(), CLD_STOPPED),
+            WaitType::Continued => (Signal::SIGCONT.into_raw(), CLD_CONTINUED),
         }
     }
 }

+ 2 - 1
src/kernel/task/process_group.rs

@@ -1,9 +1,10 @@
-use super::{Process, ProcessList, Session, Signal};
+use super::{Process, ProcessList, Session};
 use alloc::{
     collections::btree_map::BTreeMap,
     sync::{Arc, Weak},
 };
 use eonix_sync::{Locked, Proof, ProofMut};
+use posix_types::signal::Signal;
 
 pub struct ProcessGroupBuilder {
     pgid: Option<u32>,

+ 2 - 1
src/kernel/task/session.rs

@@ -1,4 +1,4 @@
-use super::{Process, ProcessGroup, ProcessList, Signal, Thread};
+use super::{Process, ProcessGroup, ProcessList, Thread};
 use crate::kernel::constants::EPERM;
 use crate::{kernel::Terminal, prelude::*};
 use alloc::{
@@ -6,6 +6,7 @@ use alloc::{
     sync::{Arc, Weak},
 };
 use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Proof, ProofMut, RwLock};
+use posix_types::signal::Signal;
 
 #[derive(Debug)]
 struct SessionJobControl {

+ 42 - 16
src/kernel/task/signal.rs

@@ -1,6 +1,4 @@
-mod signal;
 mod signal_action;
-mod signal_mask;
 
 use super::{ProcessList, Thread, WaitObject, WaitType};
 use crate::kernel::constants::{EFAULT, EINVAL};
@@ -14,17 +12,17 @@ use eonix_hal::trap::TrapContext;
 use eonix_runtime::task::Task;
 use eonix_sync::AsProof as _;
 use intrusive_collections::UnsafeRef;
+use posix_types::signal::{SigSet, Signal};
+use posix_types::{SIGNAL_IGNORE, SIGNAL_NOW, SIGNAL_STOP};
 use signal_action::SignalActionList;
 
-pub use signal::{Signal, SIGNAL_IGNORE, SIGNAL_NOW, SIGNAL_STOP};
 pub use signal_action::SignalAction;
-pub use signal_mask::SignalMask;
 
 pub(self) const SAVED_DATA_SIZE: usize =
-    size_of::<TrapContext>() + size_of::<FpuState>() + size_of::<SignalMask>();
+    size_of::<TrapContext>() + size_of::<FpuState>() + size_of::<SigSet>();
 
 struct SignalListInner {
-    mask: SignalMask,
+    mask: SigSet,
     pending: BinaryHeap<Reverse<Signal>>,
 
     signal_waker: Option<UnsafeRef<dyn Fn() + Send + Sync>>,
@@ -79,7 +77,7 @@ impl SignalListInner {
             (_, SignalAction::Ignore) => {}
             (SIGNAL_IGNORE!(), SignalAction::Default) => {}
             _ => {
-                self.mask.mask(SignalMask::from(signal));
+                self.mask.mask(SigSet::from(signal));
                 self.pending.push(Reverse(signal));
 
                 if matches!(signal, Signal::SIGCONT) {
@@ -102,7 +100,7 @@ impl SignalList {
     pub fn new() -> Self {
         Self {
             inner: Spin::new(SignalListInner {
-                mask: SignalMask::empty(),
+                mask: SigSet::empty(),
                 pending: BinaryHeap::new(),
                 signal_waker: None,
                 stop_waker: None,
@@ -111,19 +109,19 @@ impl SignalList {
         }
     }
 
-    pub fn get_mask(&self) -> SignalMask {
+    pub fn get_mask(&self) -> SigSet {
         self.inner.lock().mask
     }
 
-    pub fn set_mask(&self, mask: SignalMask) {
+    pub fn set_mask(&self, mask: SigSet) {
         self.inner.lock().mask = mask;
     }
 
-    pub fn mask(&self, mask: SignalMask) {
+    pub fn mask(&self, mask: SigSet) {
         self.inner.lock().mask.mask(mask)
     }
 
-    pub fn unmask(&self, mask: SignalMask) {
+    pub fn unmask(&self, mask: SigSet) {
         self.inner.lock().mask.unmask(mask)
     }
 
@@ -201,7 +199,7 @@ impl SignalList {
                 // Default actions include stopping the thread, continuing the thread and
                 // terminating the process. All these actions will block the thread or return
                 // to the thread immediately. So we can unmask these signals now.
-                self.inner.lock().mask.unmask(SignalMask::from(signal));
+                self.inner.lock().mask.unmask(SigSet::from(signal));
                 signal
             };
 
@@ -259,19 +257,47 @@ impl SignalList {
     }
 
     /// Load the signal mask, fpu state and trap context from the user stack.
-    pub fn restore(&self, trap_ctx: &mut TrapContext, fpu_state: &mut FpuState) -> KResult<()> {
-        let old_trap_ctx_vaddr = trap_ctx.get_stack_pointer() + 16 - 4;
+    pub fn restore(
+        &self,
+        trap_ctx: &mut TrapContext,
+        fpu_state: &mut FpuState,
+        old_sigreturn: bool,
+    ) -> KResult<()> {
+        #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))]
+        compile_error!("`restore` is not implemented for this architecture");
+
+        #[cfg(target_arch = "x86_64")]
+        let old_trap_ctx_vaddr = {
+            let mut old_trap_ctx_vaddr = trap_ctx.get_stack_pointer() + 16;
+
+            if old_sigreturn {
+                // Old sigreturn will pop 4 bytes off the stack. We sub them back.
+
+                use posix_types::ctypes::Long;
+                old_trap_ctx_vaddr -= size_of::<Long>();
+            }
+
+            old_trap_ctx_vaddr
+        };
+
+        #[cfg(target_arch = "riscv64")]
+        let old_trap_ctx_vaddr = {
+            debug_assert!(!old_sigreturn, "Old sigreturn is not supported on RISC-V");
+            trap_ctx.get_stack_pointer()
+        };
+
         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()?;
 
+        // 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::<SignalMask>::new_vaddr(old_mask_vaddr)?.read()?;
+        self.inner.lock().mask = UserPointer::<SigSet>::new_vaddr(old_mask_vaddr)?.read()?;
 
         Ok(())
     }

+ 0 - 114
src/kernel/task/signal/signal.rs

@@ -1,114 +0,0 @@
-use crate::kernel::constants::EINVAL;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Signal(u32);
-
-impl Signal {
-    pub const SIGHUP: Signal = Signal(1);
-    pub const SIGINT: Signal = Signal(2);
-    pub const SIGQUIT: Signal = Signal(3);
-    pub const SIGILL: Signal = Signal(4);
-    pub const SIGTRAP: Signal = Signal(5);
-    pub const SIGABRT: Signal = Signal(6);
-    pub const SIGIOT: Signal = Signal(6);
-    pub const SIGBUS: Signal = Signal(7);
-    pub const SIGFPE: Signal = Signal(8);
-    pub const SIGKILL: Signal = Signal(9);
-    pub const SIGUSR1: Signal = Signal(10);
-    pub const SIGSEGV: Signal = Signal(11);
-    pub const SIGUSR2: Signal = Signal(12);
-    pub const SIGPIPE: Signal = Signal(13);
-    pub const SIGALRM: Signal = Signal(14);
-    pub const SIGTERM: Signal = Signal(15);
-    pub const SIGSTKFLT: Signal = Signal(16);
-    pub const SIGCHLD: Signal = Signal(17);
-    pub const SIGCONT: Signal = Signal(18);
-    pub const SIGSTOP: Signal = Signal(19);
-    pub const SIGTSTP: Signal = Signal(20);
-    pub const SIGTTIN: Signal = Signal(21);
-    pub const SIGTTOU: Signal = Signal(22);
-    pub const SIGURG: Signal = Signal(23);
-    pub const SIGXCPU: Signal = Signal(24);
-    pub const SIGXFSZ: Signal = Signal(25);
-    pub const SIGVTALRM: Signal = Signal(26);
-    pub const SIGPROF: Signal = Signal(27);
-    pub const SIGWINCH: Signal = Signal(28);
-    pub const SIGIO: Signal = Signal(29);
-    pub const SIGPOLL: Signal = Signal(29);
-    pub const SIGPWR: Signal = Signal(30);
-    pub const SIGSYS: Signal = Signal(31);
-
-    pub const SIGNUM_MIN: u32 = 1;
-    pub const SIGNUM_MAX: u32 = 64;
-}
-
-#[macro_export]
-macro_rules! SIGNAL_IGNORE {
-    () => {
-        $crate::kernel::task::Signal::SIGCHLD
-            | $crate::kernel::task::Signal::SIGURG
-            | $crate::kernel::task::Signal::SIGWINCH
-    };
-}
-
-#[macro_export]
-macro_rules! SIGNAL_NOW {
-    () => {
-        $crate::kernel::task::Signal::SIGKILL | $crate::kernel::task::Signal::SIGSTOP
-    };
-}
-
-#[macro_export]
-macro_rules! SIGNAL_COREDUMP {
-    () => {
-        $crate::kernel::task::Signal::SIGQUIT
-            | $crate::kernel::task::Signal::SIGILL
-            | $crate::kernel::task::Signal::SIGABRT
-            | $crate::kernel::task::Signal::SIGFPE
-            | $crate::kernel::task::Signal::SIGSEGV
-            | $crate::kernel::task::Signal::SIGBUS
-            | $crate::kernel::task::Signal::SIGTRAP
-            | $crate::kernel::task::Signal::SIGSYS
-            | $crate::kernel::task::Signal::SIGXCPU
-            | $crate::kernel::task::Signal::SIGXFSZ
-    };
-}
-
-#[macro_export]
-macro_rules! SIGNAL_STOP {
-    () => {
-        $crate::kernel::task::Signal::SIGSTOP
-            | $crate::kernel::task::Signal::SIGTSTP
-            | $crate::kernel::task::Signal::SIGTTIN
-            | $crate::kernel::task::Signal::SIGTTOU
-    };
-}
-
-impl TryFrom<u32> for Signal {
-    type Error = u32;
-
-    fn try_from(signum: u32) -> Result<Self, Self::Error> {
-        match signum {
-            Self::SIGNUM_MIN..=Self::SIGNUM_MAX => Ok(Self(signum)),
-            _ => Err(EINVAL),
-        }
-    }
-}
-
-impl From<Signal> for u32 {
-    fn from(signal: Signal) -> Self {
-        let Signal(signum) = signal;
-        signum
-    }
-}
-
-impl From<Signal> for SignalMask {
-    fn from(signal: Signal) -> Self {
-        let signum = u32::from(signal);
-        SignalMask::new(1 << (signum - 1))
-    }
-}
-
-use super::SignalMask;
-
-pub use {SIGNAL_IGNORE, SIGNAL_NOW, SIGNAL_STOP};

+ 109 - 37
src/kernel/task/signal/signal_action.rs

@@ -1,27 +1,65 @@
-use super::{KResult, Signal, SignalMask, SAVED_DATA_SIZE};
+use super::{KResult, SAVED_DATA_SIZE};
 use crate::{
     io::BufferFill as _,
     kernel::{
-        constants::{EFAULT, EINVAL, ENOSYS},
+        constants::{EFAULT, EINVAL},
         user::UserBuffer,
     },
-    SIGNAL_NOW,
 };
 use alloc::{collections::btree_map::BTreeMap, sync::Arc};
-use core::num::NonZero;
+use core::arch::naked_asm;
 use eonix_hal::{fpu::FpuState, traits::trap::RawTrapContext, trap::TrapContext};
 use eonix_mm::address::{Addr as _, AddrOps as _, VAddr};
 use eonix_sync::Spin;
-use posix_types::signal::{SigAction, TryFromSigAction};
+use posix_types::{
+    ctypes::Long,
+    signal::{SigAction, SigActionHandler, SigActionRestorer, SigSet, Signal, TryFromSigAction},
+    SIGNAL_NOW,
+};
+
+#[cfg(target_arch = "x86_64")]
+#[unsafe(naked)]
+#[unsafe(link_section = ".vdso.sigreturn")]
+unsafe extern "C" fn vdso_sigreturn() {
+    naked_asm!(
+        "pop %rax",
+        "mov ${sys_sigreturn}, %eax",
+        "int $0x80",
+        sys_sigreturn = const posix_types::syscall_no::SYS_SIGRETURN,
+        options(att_syntax),
+    );
+}
+
+#[unsafe(naked)]
+#[unsafe(link_section = ".vdso.rt_sigreturn")]
+unsafe extern "C" fn vdso_rt_sigreturn() {
+    #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))]
+    compile_error!("rt_sigreturn is not implemented for this architecture");
+
+    #[cfg(target_arch = "riscv64")]
+    naked_asm!(
+        "li a7, {sys_rt_sigreturn}",
+        "ecall",
+        sys_rt_sigreturn = const posix_types::syscall_no::SYS_RT_SIGRETURN,
+    );
+
+    #[cfg(target_arch = "x86_64")]
+    naked_asm!(
+        "mov ${sys_rt_sigreturn}, %eax",
+        "int $0x80",
+        sys_rt_sigreturn = const posix_types::syscall_no::SYS_RT_SIGRETURN,
+        options(att_syntax),
+    );
+}
 
 #[derive(Debug, Clone, Copy)]
 pub enum SignalAction {
     Default,
     Ignore,
     SimpleHandler {
-        handler: VAddr,
-        restorer: Option<VAddr>,
-        mask: SignalMask,
+        handler: SigActionHandler,
+        restorer: Option<SigActionRestorer>,
+        mask: SigSet,
     },
 }
 
@@ -81,7 +119,7 @@ impl SignalAction {
     pub(super) fn handle(
         self,
         signal: Signal,
-        old_mask: SignalMask,
+        old_mask: SigSet,
         trap_ctx: &mut TrapContext,
         fpu_state: &mut FpuState,
     ) -> KResult<()> {
@@ -92,17 +130,16 @@ impl SignalAction {
             unreachable!("Default and Ignore actions should not be handled here");
         };
 
-        let Some(restorer) = restorer else {
-            // We don't accept signal handlers with no signal restorers for now.
-            return Err(ENOSYS)?;
-        };
-
         let current_sp = VAddr::from(trap_ctx.get_stack_pointer());
 
+        #[cfg(target_arch = "x86_64")]
         // Save current interrupt context to 128 bytes above current user stack
         // (in order to keep away from x86 red zone) and align to 16 bytes.
         let saved_data_addr = (current_sp - 128 - SAVED_DATA_SIZE).floor_to(16);
 
+        #[cfg(not(target_arch = "x86_64"))]
+        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)?;
 
@@ -110,16 +147,53 @@ impl SignalAction {
         saved_data_buffer.copy(fpu_state)?.ok_or(EFAULT)?;
         saved_data_buffer.copy(&old_mask)?.ok_or(EFAULT)?;
 
-        // We need to push the arguments to the handler and then save the return address.
-        let new_sp = saved_data_addr - 16 - 4;
-        let restorer_address = restorer.addr() as u32;
+        let return_address = if let Some(restorer) = restorer {
+            restorer.addr().addr()
+        } else {
+            #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))]
+            compile_error!("`vdso_sigreturn` is not implemented for this architecture");
+
+            #[cfg(target_arch = "x86_64")]
+            {
+                // TODO: Check and use `vdso_rt_sigreturn` for x86 as well.
+                static VDSO_SIGRETURN_ADDR: &'static unsafe extern "C" fn() =
+                    &(vdso_rt_sigreturn as unsafe extern "C" fn());
+
+                unsafe {
+                    // SAFETY: To prevent the compiler from optimizing this into `la` instructions
+                    //         and causing a linking error.
+                    (VDSO_SIGRETURN_ADDR as *const _ as *const usize).read_volatile()
+                }
+            }
+
+            #[cfg(target_arch = "riscv64")]
+            {
+                static VDSO_RT_SIGRETURN_ADDR: &'static unsafe extern "C" fn() =
+                    &(vdso_rt_sigreturn as unsafe extern "C" fn());
+
+                unsafe {
+                    // SAFETY: To prevent the compiler from optimizing this into `la` instructions
+                    //         and causing a linking error.
+                    (VDSO_RT_SIGRETURN_ADDR as *const _ as *const usize).read_volatile()
+                }
+            }
+        };
+
+        trap_ctx.set_user_call_frame(
+            handler.addr().addr(),
+            Some(saved_data_addr.addr()),
+            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())?;
+                for ch in data.iter() {
+                    buffer.copy(&ch)?.ok_or(EFAULT)?;
+                }
 
-        let mut stack = UserBuffer::new(new_sp.addr() as *mut u8, 4 + 4)?;
-        stack.copy(&restorer_address)?.ok_or(EFAULT)?; // Restorer address
-        stack.copy(&u32::from(signal))?.ok_or(EFAULT)?; // The argument to the handler
+                Ok(())
+            },
+        )?;
 
-        trap_ctx.set_program_counter(handler.addr());
-        trap_ctx.set_stack_pointer(new_sp.addr());
         Ok(())
     }
 }
@@ -151,9 +225,9 @@ impl TryFromSigAction for SignalAction {
 
     fn new() -> Self {
         Self::SimpleHandler {
-            handler: VAddr::NULL,
+            handler: SigActionHandler::null(),
             restorer: None,
-            mask: SignalMask::empty(),
+            mask: SigSet::empty(),
         }
     }
 
@@ -161,28 +235,28 @@ impl TryFromSigAction for SignalAction {
         Err(EINVAL)
     }
 
-    fn handler(mut self, handler_addr: usize) -> Result<Self, Self::Error> {
+    fn handler(mut self, new_handler: SigActionHandler) -> Self {
         if let Self::SimpleHandler { handler, .. } = &mut self {
-            *handler = VAddr::from(handler_addr);
-            Ok(self)
+            *handler = new_handler;
+            self
         } else {
             unreachable!()
         }
     }
 
-    fn restorer(mut self, restorer_addr: usize) -> Result<Self, Self::Error> {
+    fn restorer(mut self, new_restorer: SigActionRestorer) -> Self {
         if let Self::SimpleHandler { restorer, .. } = &mut self {
-            *restorer = NonZero::new(restorer_addr).map(|x| VAddr::from(x.get()));
-            Ok(self)
+            *restorer = Some(new_restorer);
+            self
         } else {
             unreachable!()
         }
     }
 
-    fn mask(mut self, mask_value: u64) -> Result<Self, Self::Error> {
+    fn mask(mut self, new_mask: SigSet) -> Self {
         if let Self::SimpleHandler { mask, .. } = &mut self {
-            *mask = SignalMask::from(mask_value);
-            Ok(self)
+            *mask = new_mask;
+            self
         } else {
             unreachable!()
         }
@@ -199,12 +273,10 @@ impl From<SignalAction> for SigAction {
                 restorer,
                 mask,
             } => {
-                let action = SigAction::new()
-                    .handler(handler.addr())
-                    .mask(u64::from(mask));
+                let action = SigAction::new().handler(handler).mask(mask);
 
                 if let Some(restorer) = restorer {
-                    action.restorer(restorer.addr())
+                    action.restorer(restorer)
                 } else {
                     action
                 }

+ 0 - 40
src/kernel/task/signal/signal_mask.rs

@@ -1,40 +0,0 @@
-use super::Signal;
-
-#[derive(Debug, Clone, Copy)]
-pub struct SignalMask(u64);
-
-impl SignalMask {
-    pub(super) const fn new(mask: u64) -> Self {
-        Self(mask)
-    }
-
-    pub(super) const fn empty() -> Self {
-        Self(0)
-    }
-
-    pub fn mask(&mut self, mask: Self) {
-        self.0 |= mask.0;
-    }
-
-    pub fn unmask(&mut self, mask: Self) {
-        self.0 &= !mask.0;
-    }
-
-    pub fn include(&self, signal: Signal) -> bool {
-        let signal_mask = Self::from(signal);
-        self.0 & signal_mask.0 != 0
-    }
-}
-
-impl From<SignalMask> for u64 {
-    fn from(value: SignalMask) -> Self {
-        let SignalMask(mask) = value;
-        mask
-    }
-}
-
-impl From<u64> for SignalMask {
-    fn from(mask: u64) -> Self {
-        Self(mask)
-    }
-}

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

@@ -1,5 +1,5 @@
 use super::{
-    signal::{RaiseResult, Signal, SignalList},
+    signal::{RaiseResult, SignalList},
     Process, ProcessList, WaitType,
 };
 use crate::{
@@ -36,6 +36,7 @@ use eonix_mm::address::{Addr as _, VAddr};
 use eonix_runtime::run::{Contexted, Run, RunState};
 use eonix_sync::AsProofMut as _;
 use pointers::BorrowedArc;
+use posix_types::signal::Signal;
 
 #[eonix_percpu::define_percpu]
 static CURRENT_THREAD: Option<NonNull<Thread>> = None;

+ 2 - 1
src/kernel/terminal.rs

@@ -1,5 +1,5 @@
 use super::{
-    task::{ProcessList, Session, Signal, Thread},
+    task::{ProcessList, Session, Thread},
     user::{UserPointer, UserPointerMut},
 };
 use crate::kernel::constants::{EINTR, ENOTTY, EPERM};
@@ -12,6 +12,7 @@ use bitflags::bitflags;
 use eonix_log::ConsoleWrite;
 use eonix_runtime::task::Task;
 use eonix_sync::{AsProof as _, Mutex};
+use posix_types::signal::Signal;
 
 const BUFFER_SIZE: usize = 4096;
 

+ 2 - 3
src/kernel/vfs/file.rs

@@ -8,7 +8,7 @@ use crate::{
     kernel::{
         constants::{TCGETS, TCSETS, TIOCGPGRP, TIOCGWINSZ, TIOCSPGRP},
         mem::{paging::Page, AsMemoryBlock as _},
-        task::{Signal, Thread},
+        task::Thread,
         terminal::{Terminal, TerminalIORequest},
         user::{UserPointer, UserPointerMut},
         CharDevice,
@@ -27,7 +27,7 @@ use bitflags::bitflags;
 use core::{ops::ControlFlow, sync::atomic::Ordering};
 use eonix_runtime::task::Task;
 use eonix_sync::Mutex;
-use posix_types::stat::StatX;
+use posix_types::{signal::Signal, stat::StatX};
 
 pub struct InodeFile {
     read: bool,
@@ -103,7 +103,6 @@ impl Drop for PipeWriteEnd {
 }
 
 fn send_sigpipe_to_current() {
-    // SAFETY: current_thread is always valid.
     let current = Thread::current();
     current.raise(Signal::SIGPIPE);
 }