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
__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]

View File

@ -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,7 +176,7 @@ 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

View File

@ -197,11 +197,10 @@ impl Process {
// TODO a way to terminate a single thread?
/// Terminates a process.
pub fn exit<I: Into<ExitCode>>(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);

View File

@ -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<ThreadInner>,
exit_wait: Wait,
exit_status: InitOnce<ExitCode>,
pub(super) ctx: UnsafeCell<Context>,
signal_ctx: UnsafeCell<Context>,
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();
}
}

View File

@ -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<usize, Errno> {
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 => {

View File

@ -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;

View File

@ -188,7 +188,7 @@ pub fn sys_fstatat(
///
/// System call
#[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| {
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
}
}

View File

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

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::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<F, T>
where
@ -16,24 +18,67 @@ where
T: Send + 'static,
{
closure: F,
result: Arc<UnsafeCell<MaybeUninit<T>>>,
result: ThreadPacket<T>,
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> {
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> {
pub fn join(self) -> Result<T, ()> {
pub fn join(self) -> ThreadResult<T> {
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, T>(f: F) -> JoinHandle<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<NativeData<F, T>> = 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)

View File

@ -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;

View File

@ -27,7 +27,7 @@ fn execute(line: &str) -> Result<ExitCode, Errno> {
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))