Pārlūkot izejas kodu

feat: impl vdso for all architectures and sigreturn for riscv64

greatbridf 7 mēneši atpakaļ
vecāks
revīzija
c2eab5d866
33 mainītis faili ar 754 papildinājumiem un 334 dzēšanām
  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);
 }