feature: thread::current() using tpidr_el0

This commit is contained in:
Mark Poliakov 2021-11-20 15:46:38 +02:00
parent 6eac5287a2
commit 7c622a78f8
12 changed files with 127 additions and 91 deletions

View File

@ -32,27 +32,6 @@ __aa64_ctx_enter_kernel:
eret eret
__aa64_ctx_enter_from_fork: __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] ldp x0, x1, [sp, #16 * 0]
msr sp_el0, x0 msr sp_el0, x0
msr elr_el1, x1 msr elr_el1, x1
@ -82,7 +61,8 @@ __aa64_ctx_switch:
stp x27, x28, [sp, #16 * 4] stp x27, x28, [sp, #16 * 4]
stp x29, x30, [sp, #16 * 5] stp x29, x30, [sp, #16 * 5]
mrs x19, TTBR0_EL1 mrs x19, TTBR0_EL1
stp x19, xzr, [sp, #16 * 6] mrs x20, TPIDR_EL0
stp x19, x20, [sp, #16 * 6]
mov x19, sp mov x19, sp
str x19, [x1] str x19, [x1]
@ -90,8 +70,9 @@ __aa64_ctx_switch_to:
ldr x0, [x0] ldr x0, [x0]
mov sp, x0 mov sp, x0
ldp x19, xzr, [sp, #16 * 6] ldp x19, x20, [sp, #16 * 6]
msr TTBR0_EL1, x19 msr TTBR0_EL1, x19
msr TPIDR_EL0, x20
ldp x19, x20, [sp, #16 * 0] ldp x19, x20, [sp, #16 * 0]
ldp x21, x22, [sp, #16 * 1] ldp x21, x22, [sp, #16 * 1]
ldp x23, x24, [sp, #16 * 2] ldp x23, x24, [sp, #16 * 2]

View File

@ -67,7 +67,7 @@ impl Context {
stack.push(frame.sp_el0 as usize); stack.push(frame.sp_el0 as usize);
// Setup common // Setup common
stack.push(0); stack.push(0); // tpidr_el0
stack.push(ttbr0); stack.push(ttbr0);
stack.push(__aa64_ctx_enter_from_fork as usize); // x30/lr stack.push(__aa64_ctx_enter_from_fork as usize); // x30/lr
stack.push(frame.x[29]); // x29 stack.push(frame.x[29]); // x29
@ -96,7 +96,7 @@ impl Context {
stack.push(entry); stack.push(entry);
stack.push(arg); stack.push(arg);
stack.push(/* ttbr0 */ 0); stack.push(0);
stack.push(ustack); stack.push(ustack);
stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0); stack.setup_common(__aa64_ctx_enter_user as usize, ttbr0);
@ -176,7 +176,7 @@ impl Stack {
} }
pub fn setup_common(&mut self, entry: usize, ttbr: usize) { pub fn setup_common(&mut self, entry: usize, ttbr: usize) {
self.push(0); self.push(0); // tpidr_el0
self.push(ttbr); self.push(ttbr);
self.push(entry); // x30/lr self.push(entry); // x30/lr
self.push(0); // x29 self.push(0); // x29

View File

@ -197,11 +197,10 @@ impl Process {
// TODO a way to terminate a single thread? // TODO a way to terminate a single thread?
/// Terminates a process. /// Terminates a process.
pub fn exit<I: Into<ExitCode>>(status: I) { pub fn exit(status: ExitCode) {
unsafe { unsafe {
asm!("msr daifclr, #0xF"); asm!("msr daifclr, #0xF");
} }
let status = status.into();
let thread = Thread::current(); let thread = Thread::current();
let process = thread.owner().unwrap(); let process = thread.owner().unwrap();
let mut lock = process.inner.lock(); let mut lock = process.inner.lock();
@ -213,7 +212,7 @@ impl Process {
for &tid in lock.threads.iter() { for &tid in lock.threads.iter() {
debugln!("Dequeue {:?}", tid); debugln!("Dequeue {:?}", tid);
Thread::get(tid).unwrap().terminate(); Thread::get(tid).unwrap().terminate(status);
SCHED.dequeue(tid); SCHED.dequeue(tid);
} }
SCHED.debug(); SCHED.debug();
@ -234,7 +233,7 @@ impl Process {
panic!("This code should never run"); panic!("This code should never run");
} }
pub fn exit_thread(thread: ThreadRef) { pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
let switch = { let switch = {
let switch = thread.state() == ThreadState::Running; let switch = thread.state() == ThreadState::Running;
let process = thread.owner().unwrap(); let process = thread.owner().unwrap();
@ -244,13 +243,13 @@ impl Process {
if lock.threads.len() == 1 { if lock.threads.len() == 1 {
// TODO call Process::exit instead? // TODO call Process::exit instead?
drop(lock); drop(lock);
Process::exit(ExitCode::from(0)); Process::exit(status);
panic!(); panic!();
} }
lock.threads.retain(|&e| e != tid); lock.threads.retain(|&e| e != tid);
thread.terminate(); thread.terminate(status);
SCHED.dequeue(tid); SCHED.dequeue(tid);
debugln!("Thread {} terminated", tid); debugln!("Thread {} terminated", tid);

View File

@ -1,10 +1,11 @@
use crate::arch::aarch64::exception::ExceptionFrame; use crate::arch::aarch64::exception::ExceptionFrame;
use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS}; use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS};
use crate::sync::IrqSafeSpinLock; use crate::sync::IrqSafeSpinLock;
use crate::util::InitOnce;
use alloc::{rc::Rc, vec::Vec}; use alloc::{rc::Rc, vec::Vec};
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicU32, Ordering}; 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}; pub use crate::arch::platform::context::{self, Context};
@ -36,6 +37,7 @@ struct ThreadInner {
pub struct Thread { pub struct Thread {
inner: IrqSafeSpinLock<ThreadInner>, inner: IrqSafeSpinLock<ThreadInner>,
exit_wait: Wait, exit_wait: Wait,
exit_status: InitOnce<ExitCode>,
pub(super) ctx: UnsafeCell<Context>, pub(super) ctx: UnsafeCell<Context>,
signal_ctx: UnsafeCell<Context>, signal_ctx: UnsafeCell<Context>,
signal_pending: AtomicU32, signal_pending: AtomicU32,
@ -70,6 +72,7 @@ impl Thread {
signal_ctx: UnsafeCell::new(Context::empty()), signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0), signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(), exit_wait: Wait::new(),
exit_status: InitOnce::new(),
inner: IrqSafeSpinLock::new(ThreadInner { inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0, signal_entry: 0,
signal_stack: 0, signal_stack: 0,
@ -100,6 +103,7 @@ impl Thread {
signal_ctx: UnsafeCell::new(Context::empty()), signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0), signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(), exit_wait: Wait::new(),
exit_status: InitOnce::new(),
inner: IrqSafeSpinLock::new(ThreadInner { inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0, signal_entry: 0,
signal_stack: 0, signal_stack: 0,
@ -127,6 +131,7 @@ impl Thread {
signal_ctx: UnsafeCell::new(Context::empty()), signal_ctx: UnsafeCell::new(Context::empty()),
signal_pending: AtomicU32::new(0), signal_pending: AtomicU32::new(0),
exit_wait: Wait::new(), exit_wait: Wait::new(),
exit_status: InitOnce::new(),
inner: IrqSafeSpinLock::new(ThreadInner { inner: IrqSafeSpinLock::new(ThreadInner {
signal_entry: 0, signal_entry: 0,
signal_stack: 0, signal_stack: 0,
@ -295,7 +300,7 @@ impl Thread {
let mut lock = self.inner.lock(); let mut lock = self.inner.lock();
if lock.signal_entry == 0 || lock.signal_stack == 0 { if lock.signal_entry == 0 || lock.signal_stack == 0 {
drop(lock); drop(lock);
Process::exit_thread(self); Process::exit_thread(self, ExitCode::from(-1));
panic!(); panic!();
} }
@ -322,7 +327,7 @@ impl Thread {
} }
} }
pub fn terminate(&self) { pub fn terminate(&self, status: ExitCode) {
let mut lock = self.inner.lock(); let mut lock = self.inner.lock();
lock.state = State::Finished; lock.state = State::Finished;
let tid = lock.id; let tid = lock.id;
@ -331,6 +336,7 @@ impl Thread {
if let Some(wait) = wait { if let Some(wait) = wait {
wait.abort(tid); wait.abort(tid);
} }
self.exit_status.init(status);
self.exit_wait.wakeup_all(); self.exit_wait.wakeup_all();
} }
} }

View File

@ -10,7 +10,7 @@ use libsys::{
abi, abi,
error::Errno, error::Errno,
ioctl::IoctlCmd, ioctl::IoctlCmd,
proc::Pid, proc::{ExitCode, Pid},
signal::{Signal, SignalDestination}, signal::{Signal, SignalDestination},
stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH}, stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH},
traits::{Read, Write}, traits::{Read, Write},
@ -55,13 +55,16 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
match num { match num {
// Process management system calls // Process management system calls
abi::SYS_EXIT => { abi::SYS_EXIT => {
Process::exit(args[0] as i32); Process::exit(ExitCode::from(args[0] as i32));
unreachable!(); unreachable!();
} }
abi::SYS_EX_THREAD_EXIT => { abi::SYS_EX_THREAD_EXIT => {
Process::exit_thread(Thread::current()); Process::exit_thread(Thread::current(), ExitCode::from(args[0] as i32));
unreachable!(); unreachable!();
}, },
abi::SYS_EX_GETTID => {
Ok(Thread::current().id() as usize)
},
// I/O system calls // I/O system calls
abi::SYS_OPENAT => { abi::SYS_OPENAT => {

View File

@ -8,6 +8,7 @@ pub const SYS_EX_CLONE: usize = 133;
pub const SYS_EX_YIELD: usize = 134; pub const SYS_EX_YIELD: usize = 134;
pub const SYS_EX_THREAD_EXIT: usize = 135; pub const SYS_EX_THREAD_EXIT: usize = 135;
pub const SYS_EX_THREAD_WAIT: usize = 136; pub const SYS_EX_THREAD_WAIT: usize = 136;
pub const SYS_EX_GETTID: usize = 137;
pub const SYS_EXIT: usize = 1; pub const SYS_EXIT: usize = 1;
pub const SYS_READ: usize = 2; 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_IOCTL: usize = 10;
pub const SYS_SELECT: usize = 11; pub const SYS_SELECT: usize = 11;
pub const SYS_FACCESSAT: usize = 12; pub const SYS_FACCESSAT: usize = 12;
// pub const SYS_GETPID: usize = 13;

View File

@ -188,7 +188,7 @@ pub fn sys_fstatat(
/// ///
/// System call /// System call
#[inline(always)] #[inline(always)]
pub fn sys_fork() -> Result<Option<Pid>, Errno> { pub unsafe fn sys_fork() -> Result<Option<Pid>, Errno> {
Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| { Errno::from_syscall(unsafe { syscall!(abi::SYS_FORK) }).map(|res| {
if res != 0 { if res != 0 {
Some(unsafe { Pid::from_raw(res as u32) }) 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
}
}

View File

@ -16,21 +16,8 @@ pub mod os;
pub mod sys; pub mod sys;
pub mod sync; pub mod sync;
pub mod thread; 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"] #[link_section = ".text._start"]
#[no_mangle] #[no_mangle]
@ -40,11 +27,7 @@ extern "C" fn _start(_arg: usize) -> ! {
} }
unsafe { unsafe {
sys::sys_ex_signal( thread::init_main();
_signal_handler as usize,
SIGNAL_STACK.as_ptr() as usize + 4096,
)
.unwrap();
} }
let res = unsafe { main() }; let res = unsafe { main() };
@ -53,8 +36,9 @@ extern "C" fn _start(_arg: usize) -> ! {
#[panic_handler] #[panic_handler]
fn panic_handler(pi: &PanicInfo) -> ! { 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) // 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)); sys::sys_exit(ExitCode::from(-1));
} }

13
libusr/src/signal.rs Normal file
View File

@ -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();
}

View File

@ -2,12 +2,14 @@ use alloc::{boxed::Box, sync::Arc, vec};
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use libsys::{ 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, error::Errno,
proc::ExitCode, proc::ExitCode,
}; };
use core::sync::atomic::{AtomicU32, Ordering};
use crate::trace; use core::any::Any;
use crate::{trace, signal};
use core::fmt;
struct NativeData<F, T> struct NativeData<F, T>
where where
@ -16,24 +18,67 @@ where
T: Send + 'static, T: Send + 'static,
{ {
closure: F, closure: F,
result: Arc<UnsafeCell<MaybeUninit<T>>>, result: ThreadPacket<T>,
stack: usize, stack: usize,
} }
#[derive(Clone)]
pub struct Thread {
id: u32
}
pub type ThreadResult<T> = Result<T, Box<dyn Any + Send + Sync>>;
pub type ThreadPacket<T> = Arc<UnsafeCell<MaybeUninit<ThreadResult<T>>>>;
pub struct JoinHandle<T> { pub struct JoinHandle<T> {
native: u32, native: u32,
result: Arc<UnsafeCell<MaybeUninit<T>>>, result: ThreadPacket<T>
}
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<T> JoinHandle<T> { impl<T> JoinHandle<T> {
pub fn join(self) -> Result<T, ()> { pub fn join(self) -> ThreadResult<T> {
sys_ex_thread_wait(self.native).unwrap(); sys_ex_thread_wait(self.native).unwrap();
if let Ok(result) = Arc::try_unwrap(self.result) { unsafe { Arc::try_unwrap(self.result).unwrap().into_inner().assume_init() }
Ok(unsafe { result.into_inner().assume_init() })
} else {
Err(())
} }
} }
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, T>(f: F) -> JoinHandle<T> pub fn spawn<F, T>(f: F) -> JoinHandle<T>
@ -57,18 +102,14 @@ where
let mut signal_stack = vec![0u8; 8192]; let mut signal_stack = vec![0u8; 8192];
unsafe { unsafe {
sys_ex_signal( init_common(signal_stack.as_mut_ptr().add(signal_stack.len()));
crate::_signal_handler as usize,
signal_stack.as_mut_ptr() as usize + signal_stack.len(),
)
.unwrap();
} }
let data: Box<NativeData<F, T>> = unsafe { Box::from_raw(data) }; let data: Box<NativeData<F, T>> = unsafe { Box::from_raw(data) };
let res = (data.closure)(); let res = (data.closure)();
unsafe { unsafe {
(&mut *data.result.get()).write(res); (&mut *data.result.get()).write(Ok(res));
} }
(data.stack, 8192) (data.stack, 8192)

View File

@ -7,7 +7,7 @@ extern crate libusr;
#[no_mangle] #[no_mangle]
fn main() -> i32 { fn main() -> i32 {
let pid = libusr::sys::sys_fork().unwrap(); let pid = unsafe { libusr::sys::sys_fork().unwrap() };
if let Some(pid) = pid { if let Some(pid) = pid {
let mut status = 0; let mut status = 0;

View File

@ -27,7 +27,7 @@ fn execute(line: &str) -> Result<ExitCode, Errno> {
let mut words = line.split(' '); let mut words = line.split(' ');
let cmd = words.next().unwrap(); let cmd = words.next().unwrap();
if let Some(pid) = sys_fork()? { if let Some(pid) = unsafe { sys_fork()? } {
let mut status = 0; let mut status = 0;
sys_waitpid(pid, &mut status)?; sys_waitpid(pid, &mut status)?;
Ok(ExitCode::from(status)) Ok(ExitCode::from(status))