From 7c622a78f81102942a75c77047cd43f79c14de3e Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 20 Nov 2021 15:46:38 +0200 Subject: [PATCH] feature: thread::current() using tpidr_el0 --- kernel/src/arch/aarch64/context.S | 27 ++--------- kernel/src/arch/aarch64/context.rs | 30 ++++++------ kernel/src/proc/process.rs | 11 ++--- kernel/src/proc/thread.rs | 12 +++-- kernel/src/syscall/mod.rs | 9 ++-- libsys/src/abi.rs | 2 + libsys/src/calls.rs | 9 +++- libusr/src/lib.rs | 26 ++--------- libusr/src/signal.rs | 13 ++++++ libusr/src/thread.rs | 75 +++++++++++++++++++++++------- user/src/init/main.rs | 2 +- user/src/shell/main.rs | 2 +- 12 files changed, 127 insertions(+), 91 deletions(-) create mode 100644 libusr/src/signal.rs diff --git a/kernel/src/arch/aarch64/context.S b/kernel/src/arch/aarch64/context.S index b022526..71858c5 100644 --- a/kernel/src/arch/aarch64/context.S +++ b/kernel/src/arch/aarch64/context.S @@ -32,27 +32,6 @@ __aa64_ctx_enter_kernel: eret __aa64_ctx_enter_from_fork: - // stack.push(frame.x[18]); - // stack.push(frame.x[17]); - // stack.push(frame.x[16]); - // stack.push(frame.x[15]); - // stack.push(frame.x[14]); - // stack.push(frame.x[13]); - // stack.push(frame.x[12]); - // stack.push(frame.x[11]); - // stack.push(frame.x[10]); - // stack.push(frame.x[9]); - // stack.push(frame.x[8]); - // stack.push(frame.x[7]); - // stack.push(frame.x[6]); - // stack.push(frame.x[5]); - // stack.push(frame.x[4]); - // stack.push(frame.x[3]); - // stack.push(frame.x[2]); - // stack.push(frame.x[1]); - - // stack.push(frame.elr_el1 as usize); - // stack.push(frame.sp_el0 as usize); ldp x0, x1, [sp, #16 * 0] msr sp_el0, x0 msr elr_el1, x1 @@ -82,7 +61,8 @@ __aa64_ctx_switch: stp x27, x28, [sp, #16 * 4] stp x29, x30, [sp, #16 * 5] mrs x19, TTBR0_EL1 - stp x19, xzr, [sp, #16 * 6] + mrs x20, TPIDR_EL0 + stp x19, x20, [sp, #16 * 6] mov x19, sp str x19, [x1] @@ -90,8 +70,9 @@ __aa64_ctx_switch_to: ldr x0, [x0] mov sp, x0 - ldp x19, xzr, [sp, #16 * 6] + ldp x19, x20, [sp, #16 * 6] msr TTBR0_EL1, x19 + msr TPIDR_EL0, x20 ldp x19, x20, [sp, #16 * 0] ldp x21, x22, [sp, #16 * 1] ldp x23, x24, [sp, #16 * 2] diff --git a/kernel/src/arch/aarch64/context.rs b/kernel/src/arch/aarch64/context.rs index bf77fdc..d639758 100644 --- a/kernel/src/arch/aarch64/context.rs +++ b/kernel/src/arch/aarch64/context.rs @@ -67,7 +67,7 @@ impl Context { stack.push(frame.sp_el0 as usize); // Setup common - stack.push(0); + stack.push(0); // tpidr_el0 stack.push(ttbr0); stack.push(__aa64_ctx_enter_from_fork as usize); // x30/lr stack.push(frame.x[29]); // x29 @@ -96,7 +96,7 @@ impl Context { stack.push(entry); stack.push(arg); - stack.push(/* ttbr0 */ 0); + stack.push(0); stack.push(ustack); stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0); @@ -176,20 +176,20 @@ impl Stack { } pub fn setup_common(&mut self, entry: usize, ttbr: usize) { - self.push(0); + self.push(0); // tpidr_el0 self.push(ttbr); - self.push(entry); // x30/lr - self.push(0); // x29 - self.push(0); // x28 - self.push(0); // x27 - self.push(0); // x26 - self.push(0); // x25 - self.push(0); // x24 - self.push(0); // x23 - self.push(0); // x22 - self.push(0); // x21 - self.push(0); // x20 - self.push(0); // x19 + self.push(entry); // x30/lr + self.push(0); // x29 + self.push(0); // x28 + self.push(0); // x27 + self.push(0); // x26 + self.push(0); // x25 + self.push(0); // x24 + self.push(0); // x23 + self.push(0); // x22 + self.push(0); // x21 + self.push(0); // x20 + self.push(0); // x19 } pub fn push(&mut self, value: usize) { diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index b24f58f..06bbed6 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -197,11 +197,10 @@ impl Process { // TODO a way to terminate a single thread? /// Terminates a process. - pub fn exit>(status: I) { + pub fn exit(status: ExitCode) { unsafe { asm!("msr daifclr, #0xF"); } - let status = status.into(); let thread = Thread::current(); let process = thread.owner().unwrap(); let mut lock = process.inner.lock(); @@ -213,7 +212,7 @@ impl Process { for &tid in lock.threads.iter() { debugln!("Dequeue {:?}", tid); - Thread::get(tid).unwrap().terminate(); + Thread::get(tid).unwrap().terminate(status); SCHED.dequeue(tid); } SCHED.debug(); @@ -234,7 +233,7 @@ impl Process { panic!("This code should never run"); } - pub fn exit_thread(thread: ThreadRef) { + pub fn exit_thread(thread: ThreadRef, status: ExitCode) { let switch = { let switch = thread.state() == ThreadState::Running; let process = thread.owner().unwrap(); @@ -244,13 +243,13 @@ impl Process { if lock.threads.len() == 1 { // TODO call Process::exit instead? drop(lock); - Process::exit(ExitCode::from(0)); + Process::exit(status); panic!(); } lock.threads.retain(|&e| e != tid); - thread.terminate(); + thread.terminate(status); SCHED.dequeue(tid); debugln!("Thread {} terminated", tid); diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index d848c19..3e4ed85 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -1,10 +1,11 @@ use crate::arch::aarch64::exception::ExceptionFrame; use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; use crate::sync::IrqSafeSpinLock; +use crate::util::InitOnce; use alloc::{rc::Rc, vec::Vec}; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicU32, Ordering}; -use libsys::{error::Errno, proc::Pid, signal::Signal}; +use libsys::{error::Errno, proc::{Pid, ExitCode}, signal::Signal}; pub use crate::arch::platform::context::{self, Context}; @@ -36,6 +37,7 @@ struct ThreadInner { pub struct Thread { inner: IrqSafeSpinLock, exit_wait: Wait, + exit_status: InitOnce, pub(super) ctx: UnsafeCell, signal_ctx: UnsafeCell, signal_pending: AtomicU32, @@ -70,6 +72,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -100,6 +103,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -127,6 +131,7 @@ impl Thread { signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), exit_wait: Wait::new(), + exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, signal_stack: 0, @@ -295,7 +300,7 @@ impl Thread { let mut lock = self.inner.lock(); if lock.signal_entry == 0 || lock.signal_stack == 0 { drop(lock); - Process::exit_thread(self); + Process::exit_thread(self, ExitCode::from(-1)); panic!(); } @@ -322,7 +327,7 @@ impl Thread { } } - pub fn terminate(&self) { + pub fn terminate(&self, status: ExitCode) { let mut lock = self.inner.lock(); lock.state = State::Finished; let tid = lock.id; @@ -331,6 +336,7 @@ impl Thread { if let Some(wait) = wait { wait.abort(tid); } + self.exit_status.init(status); self.exit_wait.wakeup_all(); } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index b870833..2c0892f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -10,7 +10,7 @@ use libsys::{ abi, error::Errno, ioctl::IoctlCmd, - proc::Pid, + proc::{ExitCode, Pid}, signal::{Signal, SignalDestination}, stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, traits::{Read, Write}, @@ -55,13 +55,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result { match num { // Process management system calls abi::SYS_EXIT => { - Process::exit(args[0] as i32); + Process::exit(ExitCode::from(args[0] as i32)); unreachable!(); } abi::SYS_EX_THREAD_EXIT => { - Process::exit_thread(Thread::current()); + Process::exit_thread(Thread::current(), ExitCode::from(args[0] as i32)); unreachable!(); }, + abi::SYS_EX_GETTID => { + Ok(Thread::current().id() as usize) + }, // I/O system calls abi::SYS_OPENAT => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 16ef3d7..056563e 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -8,6 +8,7 @@ pub const SYS_EX_CLONE: usize = 133; pub const SYS_EX_YIELD: usize = 134; pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EX_THREAD_WAIT: usize = 136; +pub const SYS_EX_GETTID: usize = 137; pub const SYS_EXIT: usize = 1; pub const SYS_READ: usize = 2; @@ -21,3 +22,4 @@ pub const SYS_WAITPID: usize = 9; pub const SYS_IOCTL: usize = 10; pub const SYS_SELECT: usize = 11; pub const SYS_FACCESSAT: usize = 12; +// pub const SYS_GETPID: usize = 13; diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index af430f6..8f09427 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -188,7 +188,7 @@ pub fn sys_fstatat( /// /// System call #[inline(always)] -pub fn sys_fork() -> Result, Errno> { +pub unsafe fn sys_fork() -> Result, Errno> { Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| { if res != 0 { Some(unsafe { Pid::from_raw(res as u32) }) @@ -344,3 +344,10 @@ pub fn sys_faccessat( ) }) } + +#[inline(always)] +pub fn sys_ex_gettid() -> u32 { + unsafe { + syscall!(abi::SYS_EX_GETTID) as u32 + } +} diff --git a/libusr/src/lib.rs b/libusr/src/lib.rs index c967fb3..f13a1e9 100644 --- a/libusr/src/lib.rs +++ b/libusr/src/lib.rs @@ -16,21 +16,8 @@ pub mod os; pub mod sys; pub mod sync; pub mod thread; +pub mod signal; -use sys::Signal; - -#[inline(never)] -pub(crate) extern "C" fn _signal_handler(arg: Signal) -> ! { - trace!("Entered signal handler: arg={:?}", arg); - match arg { - Signal::Interrupt | Signal::SegmentationFault => - loop {}, - _ => todo!() - } - sys::sys_ex_sigreturn(); -} - -static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; #[link_section = ".text._start"] #[no_mangle] @@ -40,11 +27,7 @@ extern "C" fn _start(_arg: usize) -> ! { } unsafe { - sys::sys_ex_signal( - _signal_handler as usize, - SIGNAL_STACK.as_ptr() as usize + 4096, - ) - .unwrap(); + thread::init_main(); } let res = unsafe { main() }; @@ -53,8 +36,9 @@ extern "C" fn _start(_arg: usize) -> ! { #[panic_handler] fn panic_handler(pi: &PanicInfo) -> ! { - // TODO handle non-main thread panics + // TODO unwind to send panic argument back to parent thread // TODO print to stdout/stderr (if available) - trace!("Panic ocurred: {}", pi); + let thread = thread::current(); + trace!("{:?} panicked: {:?}", thread, pi); sys::sys_exit(ExitCode::from(-1)); } diff --git a/libusr/src/signal.rs b/libusr/src/signal.rs new file mode 100644 index 0000000..f9d8787 --- /dev/null +++ b/libusr/src/signal.rs @@ -0,0 +1,13 @@ +use libsys::{calls::sys_ex_sigreturn, signal::Signal}; +use crate::trace; + +#[inline(never)] +pub(crate) extern "C" fn signal_handler(arg: Signal) -> ! { + trace!("Entered signal handler: arg={:?}", arg); + match arg { + Signal::Interrupt | Signal::SegmentationFault => + loop {}, + _ => todo!() + } + sys_ex_sigreturn(); +} diff --git a/libusr/src/thread.rs b/libusr/src/thread.rs index f521ce0..f08848f 100644 --- a/libusr/src/thread.rs +++ b/libusr/src/thread.rs @@ -2,12 +2,14 @@ use alloc::{boxed::Box, sync::Arc, vec}; use core::cell::UnsafeCell; use core::mem::MaybeUninit; use libsys::{ - calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait}, + calls::{sys_ex_clone, sys_ex_signal, sys_ex_thread_exit, sys_ex_thread_wait, sys_ex_gettid}, error::Errno, proc::ExitCode, }; - -use crate::trace; +use core::sync::atomic::{AtomicU32, Ordering}; +use core::any::Any; +use crate::{trace, signal}; +use core::fmt; struct NativeData where @@ -16,26 +18,69 @@ where T: Send + 'static, { closure: F, - result: Arc>>, + result: ThreadPacket, stack: usize, } +#[derive(Clone)] +pub struct Thread { + id: u32 +} + +pub type ThreadResult = Result>; +pub type ThreadPacket = Arc>>>; + pub struct JoinHandle { native: u32, - result: Arc>>, + result: ThreadPacket +} + +impl Thread { + pub const fn id(&self) -> u32 { + self.id + } +} + +impl fmt::Debug for Thread { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Thread").field("id", &self.id).finish_non_exhaustive() + } } impl JoinHandle { - pub fn join(self) -> Result { + pub fn join(self) -> ThreadResult { sys_ex_thread_wait(self.native).unwrap(); - if let Ok(result) = Arc::try_unwrap(self.result) { - Ok(unsafe { result.into_inner().assume_init() }) - } else { - Err(()) - } + unsafe { Arc::try_unwrap(self.result).unwrap().into_inner().assume_init() } } } +unsafe fn init_common(signal_stack_pointer: *mut u8) { + let tid = sys_ex_gettid(); + asm!("msr tpidr_el0, {}", in(reg) tid); + + // thread::current() should be valid at this point + + sys_ex_signal( + signal::signal_handler as usize, + signal_stack_pointer as usize + ) + .unwrap(); +} + +pub(crate) unsafe fn init_main() { + static mut SIGNAL_STACK: [u8; 4096] = [0; 4096]; + init_common(SIGNAL_STACK.as_mut_ptr().add(SIGNAL_STACK.len())) +} + +pub fn current() -> Thread { + let mut id: u32; + unsafe { + asm!("mrs {}, tpidr_el0", out(reg) id); + } + + Thread { id } +} + pub fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T, @@ -57,18 +102,14 @@ where let mut signal_stack = vec![0u8; 8192]; unsafe { - sys_ex_signal( - crate::_signal_handler as usize, - signal_stack.as_mut_ptr() as usize + signal_stack.len(), - ) - .unwrap(); + init_common(signal_stack.as_mut_ptr().add(signal_stack.len())); } let data: Box> = unsafe { Box::from_raw(data) }; let res = (data.closure)(); unsafe { - (&mut *data.result.get()).write(res); + (&mut *data.result.get()).write(Ok(res)); } (data.stack, 8192) diff --git a/user/src/init/main.rs b/user/src/init/main.rs index f033d6d..02bebcc 100644 --- a/user/src/init/main.rs +++ b/user/src/init/main.rs @@ -7,7 +7,7 @@ extern crate libusr; #[no_mangle] fn main() -> i32 { - let pid = libusr::sys::sys_fork().unwrap(); + let pid = unsafe { libusr::sys::sys_fork().unwrap() }; if let Some(pid) = pid { let mut status = 0; diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index 4425bd5..64ea822 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -27,7 +27,7 @@ fn execute(line: &str) -> Result { let mut words = line.split(' '); let cmd = words.next().unwrap(); - if let Some(pid) = sys_fork()? { + if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; sys_waitpid(pid, &mut status)?; Ok(ExitCode::from(status))