Просмотр исходного кода

partial work of making the new trap handling method work

greatbridf 8 месяцев назад
Родитель
Сommit
43016845e4

+ 15 - 4
macros/src/lib.rs

@@ -57,22 +57,32 @@ fn define_syscall_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
 
     let helper_fn = Ident::new(&format!("_do_syscall_{}", syscall_name), Span::call_site());
     let helper_fn_pointer = Ident::new(
-        &format!("SYSCALL_ENTRY_{:03}", syscall_no),
+        &format!("_SYSCALL_ENTRY_{:03}", syscall_no),
         Span::call_site(),
     );
 
     let real_fn = Ident::new(&format!("sys_{}", syscall_name), Span::call_site());
 
+    let raw_syscall_section = LitStr::new(
+        &format!(".raw_syscalls.{}", syscall_name),
+        Span::call_site(),
+    );
+    let syscall_fn_section =
+        LitStr::new(&format!(".syscall_fns.{}", syscall_name), Span::call_site());
+
     quote! {
         #[used]
         #[doc(hidden)]
-        #[link_section = ".syscalls"]
-        static #helper_fn_pointer: crate::kernel::syscall::SyscallHandler =
-            crate::kernel::syscall::SyscallHandler {
+        #[no_mangle]
+        #[link_section = #raw_syscall_section]
+        static #helper_fn_pointer: crate::kernel::syscall::RawSyscallHandler =
+            crate::kernel::syscall::RawSyscallHandler {
+                no: #syscall_no,
                 handler: #helper_fn,
                 name: #syscall_name_str,
             };
 
+        #[link_section = #syscall_fn_section]
         fn #helper_fn (
             thd: &crate::kernel::task::Thread,
             args: [usize; 6]
@@ -103,6 +113,7 @@ fn define_syscall_impl(attrs: TokenStream, item: TokenStream) -> TokenStream {
         }
 
         #(#attrs)*
+        #[link_section = #syscall_fn_section]
         #vis fn #real_fn(
             thread: &crate::kernel::task::Thread,
             #(#args),*

+ 7 - 2
src/kernel.ld

@@ -73,6 +73,7 @@ SECTIONS
         TEXT_START = .;
         *(.text)
         *(.text*)
+        KEEP(*(.syscall_fns*))
 
         . = ALIGN(0x1000);
         TEXT_END = .;
@@ -80,6 +81,8 @@ SECTIONS
 
     TEXT_PAGES = (TEXT_END - TEXT_START) / 0x1000;
 
+    RAW_SYSCALL_HANDLERS_SIZE = (_raw_syscall_handlers_end - RAW_SYSCALL_HANDLERS);
+
     .rodata :
         AT(LOADADDR(.text) + SIZEOF(.text))
     {
@@ -96,8 +99,10 @@ SECTIONS
         end_ctors = .;
 
         . = ALIGN(16);
-        SYSCALL_HANDLERS = .;
-        KEEP(*(SORT_BY_NAME(.syscalls*)));
+        RAW_SYSCALL_HANDLERS = .;
+        KEEP(*(.raw_syscalls*));
+
+        _raw_syscall_handlers_end = .;
 
         . = ALIGN(16);
         _fix_start = .;

+ 48 - 11
src/kernel/syscall.rs

@@ -1,15 +1,23 @@
 use crate::kernel::task::Thread;
+use eonix_sync::LazyLock;
 
-mod file_rw;
-mod mm;
-mod net;
-mod procops;
-mod sysinfo;
+pub mod file_rw;
+pub mod mm;
+pub mod net;
+pub mod procops;
+pub mod sysinfo;
 
 const MAX_SYSCALL_NO: usize = 512;
 
 pub struct SyscallNoReturn;
 
+#[repr(C)]
+pub(self) struct RawSyscallHandler {
+    no: usize,
+    handler: fn(&Thread, [usize; 6]) -> Option<usize>,
+    name: &'static str,
+}
+
 pub struct SyscallHandler {
     pub handler: fn(&Thread, [usize; 6]) -> Option<usize>,
     pub name: &'static str,
@@ -95,14 +103,43 @@ impl<T> FromSyscallArg for *mut T {
     }
 }
 
-pub fn syscall_handlers() -> &'static [SyscallHandler; MAX_SYSCALL_NO] {
+static SYSCALL_HANDLERS: LazyLock<[Option<SyscallHandler>; MAX_SYSCALL_NO]> = LazyLock::new(|| {
     extern "C" {
-        #[allow(improper_ctypes)]
-        static SYSCALL_HANDLERS: [SyscallHandler; MAX_SYSCALL_NO];
+        // SAFETY: `SYSCALL_HANDLERS` is defined in linker script.
+        fn RAW_SYSCALL_HANDLERS();
+        fn RAW_SYSCALL_HANDLERS_SIZE();
     }
 
-    unsafe {
-        // SAFETY: `SYSCALL_HANDLERS` is defined in linker script.
-        &SYSCALL_HANDLERS
+    // DO NOT TOUCH THESE FUNCTIONS!!!
+    // THEY ARE USED FOR KEEPING THE OBJECTS NOT STRIPPED BY THE LINKER!!!
+    file_rw::keep_alive();
+    mm::keep_alive();
+    net::keep_alive();
+    procops::keep_alive();
+    sysinfo::keep_alive();
+
+    let raw_handlers_addr = RAW_SYSCALL_HANDLERS as *const ();
+    let raw_handlers_size_byte = RAW_SYSCALL_HANDLERS_SIZE as usize;
+    assert!(raw_handlers_size_byte % size_of::<RawSyscallHandler>() == 0);
+
+    let raw_handlers_count = raw_handlers_size_byte / size_of::<RawSyscallHandler>();
+
+    let raw_handlers = unsafe {
+        core::slice::from_raw_parts(
+            raw_handlers_addr as *const RawSyscallHandler,
+            raw_handlers_count,
+        )
+    };
+
+    let mut handlers = [const { None }; MAX_SYSCALL_NO];
+
+    for &RawSyscallHandler { no, handler, name } in raw_handlers.iter() {
+        handlers[no] = Some(SyscallHandler { handler, name })
     }
+
+    handlers
+});
+
+pub fn syscall_handlers() -> &'static [Option<SyscallHandler>] {
+    SYSCALL_HANDLERS.as_ref()
 }

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

@@ -370,3 +370,5 @@ fn poll(fds: *mut UserPollFd, nfds: u32, _timeout: u32) -> KResult<u32> {
         }
     }
 }
+
+pub fn keep_alive() {}

+ 3 - 1
src/kernel/syscall/mm.rs

@@ -107,6 +107,8 @@ fn brk(addr: usize) -> KResult<usize> {
 }
 
 #[eonix_macros::define_syscall(0xdb)]
-fn do_madvise(_addr: usize, _len: usize, _advice: u32) -> KResult<()> {
+fn madvise(_addr: usize, _len: usize, _advice: u32) -> KResult<()> {
     Ok(())
 }
+
+pub fn keep_alive() {}

+ 2 - 0
src/kernel/syscall/net.rs

@@ -5,3 +5,5 @@ use crate::prelude::*;
 fn socket(_domain: u32, _socket_type: u32, _protocol: u32) -> KResult<u32> {
     Err(EINVAL)
 }
+
+pub fn keep_alive() {}

+ 10 - 8
src/kernel/syscall/procops.rs

@@ -7,8 +7,8 @@ use crate::kernel::constants::{
 };
 use crate::kernel::mem::PageBuffer;
 use crate::kernel::task::{
-    KernelStack, ProcessBuilder, ProcessList, Signal, SignalAction, SignalMask, ThreadBuilder,
-    ThreadRunnable, UserDescriptor, WaitObject, WaitType,
+    new_thread_runnable, KernelStack, ProcessBuilder, ProcessList, Signal, SignalAction,
+    SignalMask, ThreadBuilder, UserDescriptor, WaitObject, WaitType,
 };
 use crate::kernel::user::dataflow::UserString;
 use crate::kernel::user::{UserPointer, UserPointerMut};
@@ -167,17 +167,17 @@ fn execve(exec: *const u8, argv: *const u32, envp: *const u32) -> KResult<()> {
 }
 
 #[eonix_macros::define_syscall(0x01)]
-fn exit(status: u32) {
+fn exit(status: u32) -> SyscallNoReturn {
     unsafe {
         let mut procs = Task::block_on(ProcessList::get().write());
         procs.do_kill_process(&thread.process, WaitType::Exited(status));
     }
 
-    todo!()
+    SyscallNoReturn
 }
 
 #[eonix_macros::define_syscall(0xfc)]
-fn exit_group(status: u32) {
+fn exit_group(status: u32) -> SyscallNoReturn {
     sys_exit(thread, status)
 }
 
@@ -277,7 +277,7 @@ fn getuid() -> KResult<u32> {
     Ok(0)
 }
 
-#[eonix_macros::define_syscall(0xca)]
+#[eonix_macros::define_syscall(0xc9)]
 fn geteuid() -> KResult<u32> {
     // All users are root for now.
     Ok(0)
@@ -560,7 +560,7 @@ fn fork() -> u32 {
         .thread_builder(thread_builder)
         .build(&mut procs);
 
-    Scheduler::get().spawn::<KernelStack, _>(ThreadRunnable::new(new_thread));
+    Scheduler::get().spawn::<KernelStack, _>(new_thread_runnable(new_thread));
 
     new_process.pid
 }
@@ -578,7 +578,7 @@ fn sigreturn() -> KResult<SyscallNoReturn> {
                 "`sigreturn` failed in thread {} with error {err}!",
                 thread.tid
             );
-            thread.raise(Signal::SIGSEGV);
+            Task::block_on(thread.process.force_kill(Signal::SIGSEGV));
         })?;
 
     Ok(SyscallNoReturn)
@@ -589,3 +589,5 @@ fn sigreturn() -> KResult<SyscallNoReturn> {
 fn arch_prctl(option: u32, addr: u32) -> KResult<u32> {
     sys_arch_prctl(thread, option, addr)
 }
+
+pub fn keep_alive() {}

+ 4 - 1
src/kernel/syscall/sysinfo.rs

@@ -23,7 +23,8 @@ fn copy_cstr_to_array(cstr: &[u8], array: &mut [u8]) {
     array[len] = 0;
 }
 
-fn do_newuname(buffer: *mut NewUTSName) -> KResult<()> {
+#[eonix_macros::define_syscall(0x7a)]
+fn newuname(buffer: *mut NewUTSName) -> KResult<()> {
     let buffer = UserPointerMut::new(buffer)?;
     let mut uname = NewUTSName {
         sysname: [0; 65],
@@ -148,3 +149,5 @@ fn times(tms: *mut TMS) -> KResult<()> {
         tms_cstime: 0,
     })
 }
+
+pub fn keep_alive() {}

+ 1 - 1
src/kernel/task.rs

@@ -12,4 +12,4 @@ pub use process_group::ProcessGroup;
 pub use process_list::ProcessList;
 pub use session::Session;
 pub use signal::{Signal, SignalAction, SignalMask};
-pub use thread::{Thread, ThreadBuilder, ThreadRunnable, UserDescriptor};
+pub use thread::{new_thread_runnable, Thread, ThreadBuilder, UserDescriptor};

+ 6 - 1
src/kernel/task/signal.rs

@@ -256,11 +256,16 @@ 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();
+        let old_trap_ctx_vaddr = trap_ctx.get_stack_pointer() + 16 - 4;
         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()?;
+
+        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()?;
 

+ 133 - 63
src/kernel/task/thread.rs

@@ -17,10 +17,11 @@ use alloc::sync::Arc;
 use arch::{FpuState, TrapContext, UserTLS};
 use atomic_unique_refcell::AtomicUniqueRefCell;
 use core::{
+    future::Future,
     pin::Pin,
     ptr::NonNull,
     sync::atomic::{AtomicBool, Ordering},
-    task::Waker,
+    task::{Context, Poll, Waker},
 };
 use eonix_hal::{
     traits::{
@@ -38,8 +39,9 @@ use pointers::BorrowedArc;
 #[eonix_percpu::define_percpu]
 static CURRENT_THREAD: Option<NonNull<Thread>> = None;
 
-pub struct ThreadRunnable {
+pub struct ThreadRunnable<F: Future> {
     thread: Arc<Thread>,
+    future: F,
 }
 
 pub struct ThreadBuilder {
@@ -318,8 +320,19 @@ impl Thread {
 
     pub fn handle_syscall(&self, no: usize, args: [usize; 6]) -> Option<usize> {
         match syscall_handlers().get(no) {
-            Some(SyscallHandler { handler, .. }) => handler(self, args),
-            None => {
+            Some(Some(SyscallHandler {
+                handler,
+                name: _name,
+                ..
+            })) => {
+                println_trace!(
+                    "trace_syscall",
+                    "Syscall {_name}({no:#x}) on tid {:#x}",
+                    self.tid
+                );
+                handler(self, args)
+            }
+            _ => {
                 println_warn!("Syscall {no}({no:#x}) isn't implemented.");
                 self.raise(Signal::SIGSYS);
                 None
@@ -330,15 +343,115 @@ impl Thread {
     pub fn is_dead(&self) -> bool {
         self.dead.load(Ordering::SeqCst)
     }
+
+    async fn real_run(&self) {
+        while !self.is_dead() {
+            if self.signal_list.has_pending_signal() {
+                self.signal_list
+                    .handle(&mut self.trap_ctx.borrow(), &mut self.fpu_state.borrow())
+                    .await;
+            }
+
+            if self.is_dead() {
+                return;
+            }
+
+            self.fpu_state.borrow().restore();
+
+            unsafe {
+                // SAFETY: We are returning to the context of the user thread.
+                self.trap_ctx.borrow().trap_return();
+            }
+
+            self.fpu_state.borrow().save();
+
+            let trap_type = self.trap_ctx.borrow().trap_type();
+            match trap_type {
+                TrapType::Fault(Fault::PageFault(err_code)) => {
+                    let addr = arch::get_page_fault_address();
+                    let mms = &self.process.mm_list;
+                    if let Err(signal) = mms.handle_user_page_fault(addr, err_code).await {
+                        self.signal_list.raise(signal);
+                    }
+                }
+                TrapType::Fault(Fault::BadAccess) => {
+                    self.signal_list.raise(Signal::SIGSEGV);
+                }
+                TrapType::Fault(Fault::InvalidOp) => {
+                    self.signal_list.raise(Signal::SIGILL);
+                }
+                TrapType::Fault(Fault::Unknown(_)) => unimplemented!("Unhandled fault"),
+                TrapType::Irq(irqno) => default_irq_handler(irqno),
+                TrapType::Timer => {
+                    timer_interrupt();
+                    yield_now().await;
+                }
+                TrapType::Syscall { no, args } => {
+                    if let Some(retval) = self.handle_syscall(no, args) {
+                        self.trap_ctx.borrow().set_user_return_value(retval);
+                    }
+                }
+            }
+        }
+    }
+
+    pub async fn run(self: Arc<Thread>) {
+        struct ContextedRun<'a, F: Future>(F, &'a Thread);
+
+        impl<F: Future> Future for ContextedRun<'_, F> {
+            type Output = F::Output;
+
+            fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
+                let irq_state = arch::disable_irqs_save();
+                let (future, _) = unsafe {
+                    // SAFETY: We construct a pinned future and `&Thread` is `Unpin`.
+                    let me = self.as_mut().get_unchecked_mut();
+                    (Pin::new_unchecked(&mut me.0), me.1)
+                };
+
+                let retval = future.poll(ctx);
+
+                irq_state.restore();
+                retval
+            }
+        }
+
+        ContextedRun(self.real_run(), &self).await
+    }
 }
 
-impl ThreadRunnable {
-    pub fn new(thread: Arc<Thread>) -> Self {
-        Self { thread }
+async fn yield_now() {
+    struct Yield {
+        yielded: bool,
+    }
+
+    impl Future for Yield {
+        type Output = ();
+
+        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+            if self.as_mut().yielded {
+                Poll::Ready(())
+            } else {
+                self.as_mut().yielded = true;
+                cx.waker().wake_by_ref();
+                Poll::Pending
+            }
+        }
+    }
+
+    Yield { yielded: false }.await;
+}
+
+pub fn new_thread_runnable(
+    thread: Arc<Thread>,
+) -> ThreadRunnable<impl Future<Output = impl Send + 'static> + Send + 'static> {
+    ThreadRunnable {
+        thread: thread.clone(),
+        future: thread.run(),
     }
 }
 
-impl Contexted for ThreadRunnable {
+impl<F: Future> Contexted for ThreadRunnable<F> {
     fn load_running_context(&self) {
         self.thread.process.mm_list.activate();
 
@@ -364,62 +477,19 @@ impl Contexted for ThreadRunnable {
     }
 }
 
-impl Run for ThreadRunnable {
-    type Output = ();
-
-    fn run(self: Pin<&mut Self>, _waker: &Waker) -> RunState<Self::Output> {
-        let irq_state = arch::disable_irqs_save();
-
-        let run_state = loop {
-            if self.thread.is_dead() {
-                break RunState::Finished(());
-            }
-
-            if self.thread.signal_list.has_pending_signal() {
-                self.thread.signal_list.handle(
-                    &mut self.thread.trap_ctx.borrow(),
-                    &mut self.thread.fpu_state.borrow(),
-                );
-            }
-
-            if self.thread.is_dead() {
-                break RunState::Finished(());
-            }
-
-            unsafe {
-                // SAFETY: We are returning to the context of the user thread.
-                self.thread.trap_ctx.borrow().trap_return();
-            }
-
-            let trap_type = self.thread.trap_ctx.borrow().trap_type();
-            match trap_type {
-                TrapType::Fault(Fault::PageFault(err_code)) => {
-                    let addr = arch::get_page_fault_address();
-                    let mms = &self.thread.process.mm_list;
-                    mms.handle_user_page_fault(addr, err_code);
-                }
-                TrapType::Fault(Fault::BadAccess) => {
-                    self.thread.signal_list.raise(Signal::SIGSEGV);
-                }
-                TrapType::Fault(Fault::InvalidOp) => {
-                    self.thread.signal_list.raise(Signal::SIGILL);
-                }
-                TrapType::Fault(Fault::Unknown(_)) => unimplemented!("Unhandled fault"),
-                TrapType::Irq(irqno) => default_irq_handler(irqno),
-                TrapType::Timer => {
-                    timer_interrupt();
+impl<F: Future> Run for ThreadRunnable<F> {
+    type Output = F::Output;
 
-                    break RunState::Running;
-                }
-                TrapType::Syscall { no, args } => {
-                    if let Some(retval) = self.thread.handle_syscall(no, args) {
-                        self.thread.trap_ctx.borrow().set_user_return_value(retval);
-                    }
-                }
-            }
-        };
+    fn run(mut self: Pin<&mut Self>, waker: &Waker) -> RunState<Self::Output> {
+        let mut ctx = Context::from_waker(waker);
 
-        irq_state.restore();
-        run_state
+        match unsafe {
+            self.as_mut()
+                .map_unchecked_mut(|me| &mut me.future)
+                .poll(&mut ctx)
+        } {
+            Poll::Ready(output) => RunState::Finished(output),
+            Poll::Pending => RunState::Running,
+        }
     }
 }

+ 2 - 2
src/lib.rs

@@ -33,7 +33,7 @@ use eonix_runtime::{run::FutureRun, scheduler::Scheduler, task::Task};
 use kernel::{
     mem::Page,
     pcie::init_pcie,
-    task::{KernelStack, ProcessBuilder, ProcessList, ThreadBuilder, ThreadRunnable},
+    task::{new_thread_runnable, KernelStack, ProcessBuilder, ProcessList, ThreadBuilder},
     vfs::{
         dentry::Dentry,
         mount::{do_mount, MS_NOATIME, MS_NODEV, MS_NOSUID, MS_RDONLY},
@@ -177,5 +177,5 @@ async fn init_process(early_kstack_pfn: PFN) {
     // TODO!!!: Remove this.
     thread.files.open_console();
 
-    Scheduler::get().spawn::<KernelStack, _>(ThreadRunnable::new(thread));
+    Scheduler::get().spawn::<KernelStack, _>(new_thread_runnable(thread));
 }