| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- use super::{
- signal::{RaiseResult, Signal, SignalList},
- Process, ProcessList,
- };
- use crate::{
- kernel::{
- cpu::local_cpu,
- user::dataflow::CheckedUserPointer,
- vfs::{filearray::FileArray, FsContext},
- },
- prelude::*,
- };
- use alloc::sync::Arc;
- use arch::{InterruptContext, UserTLS, _arch_fork_return};
- use core::{
- arch::asm,
- pin::Pin,
- ptr::NonNull,
- sync::atomic::{AtomicUsize, Ordering},
- task::Waker,
- };
- use eonix_mm::address::{Addr as _, VAddr};
- use eonix_runtime::{
- context::ExecutionContext,
- run::{Contexted, Run, RunState},
- };
- use eonix_sync::AsProofMut as _;
- use pointers::BorrowedArc;
- struct CurrentThread {
- thread: NonNull<Thread>,
- runnable: NonNull<ThreadRunnable>,
- }
- #[eonix_percpu::define_percpu]
- static CURRENT_THREAD: Option<CurrentThread> = None;
- pub struct ThreadBuilder {
- tid: Option<u32>,
- name: Option<Arc<[u8]>>,
- process: Option<Arc<Process>>,
- files: Option<Arc<FileArray>>,
- fs_context: Option<Arc<FsContext>>,
- signal_list: Option<SignalList>,
- tls: Option<UserTLS>,
- set_child_tid: Option<usize>,
- }
- #[derive(Debug)]
- struct ThreadInner {
- /// Thread name
- name: Arc<[u8]>,
- /// Thread TLS
- tls: Option<UserTLS>,
- /// User pointer
- /// Store child thread's tid when child thread returns to user space.
- set_child_tid: usize,
- }
- pub struct Thread {
- pub tid: u32,
- pub process: Arc<Process>,
- pub files: Arc<FileArray>,
- pub fs_context: Arc<FsContext>,
- pub signal_list: SignalList,
- inner: Spin<ThreadInner>,
- }
- pub struct ThreadRunnable {
- thread: Arc<Thread>,
- /// Interrupt context for the thread initialization.
- /// We store the kernel stack pointer in one of the fields for now.
- ///
- /// TODO: A better way to store the interrupt context.
- interrupt_context: InterruptContext,
- interrupt_stack_pointer: AtomicUsize,
- return_context: ExecutionContext,
- }
- #[repr(transparent)]
- #[derive(Debug, Clone, Copy)]
- pub struct UserDescriptorFlags(u32);
- #[repr(C)]
- #[derive(Debug, Clone, Copy)]
- pub struct UserDescriptor {
- entry: u32,
- base: u32,
- limit: u32,
- flags: UserDescriptorFlags,
- }
- #[allow(dead_code)]
- impl UserDescriptorFlags {
- fn is_32bit_segment(&self) -> bool {
- self.0 & 0b1 != 0
- }
- fn contents(&self) -> u32 {
- self.0 & 0b110
- }
- fn is_read_exec_only(&self) -> bool {
- self.0 & 0b1000 != 0
- }
- fn is_limit_in_pages(&self) -> bool {
- self.0 & 0b10000 != 0
- }
- fn is_present(&self) -> bool {
- self.0 & 0b100000 == 0
- }
- fn is_usable(&self) -> bool {
- self.0 & 0b1000000 != 0
- }
- }
- impl ThreadBuilder {
- pub fn new() -> Self {
- Self {
- tid: None,
- name: None,
- process: None,
- files: None,
- fs_context: None,
- signal_list: None,
- tls: None,
- set_child_tid: None,
- }
- }
- pub fn tid(mut self, tid: u32) -> Self {
- self.tid = Some(tid);
- self
- }
- pub fn name(mut self, name: Arc<[u8]>) -> Self {
- self.name = Some(name);
- self
- }
- pub fn process(mut self, process: Arc<Process>) -> Self {
- self.process = Some(process);
- self
- }
- pub fn files(mut self, files: Arc<FileArray>) -> Self {
- self.files = Some(files);
- self
- }
- pub fn fs_context(mut self, fs_context: Arc<FsContext>) -> Self {
- self.fs_context = Some(fs_context);
- self
- }
- pub fn signal_list(mut self, signal_list: SignalList) -> Self {
- self.signal_list = Some(signal_list);
- self
- }
- pub fn tls(mut self, tls: Option<UserTLS>) -> Self {
- self.tls = tls;
- self
- }
- pub fn set_child_tid(mut self, set_child_tid: usize) -> Self {
- self.set_child_tid = Some(set_child_tid);
- self
- }
- /// Fork the thread from another thread.
- ///
- /// Sets the thread's files, fs_context, signal_list, name, tls, and set_child_tid
- pub fn fork_from(self, thread: &Thread) -> Self {
- let inner = thread.inner.lock();
- self.files(FileArray::new_cloned(&thread.files))
- .fs_context(FsContext::new_cloned(&thread.fs_context))
- .signal_list(thread.signal_list.clone())
- .name(inner.name.clone())
- .tls(inner.tls.clone())
- .set_child_tid(inner.set_child_tid)
- }
- pub fn build(self, process_list: &mut ProcessList) -> Arc<Thread> {
- let tid = self.tid.expect("TID is not set");
- let name = self.name.expect("Name is not set");
- let process = self.process.expect("Process is not set");
- let files = self.files.unwrap_or_else(|| FileArray::new());
- let fs_context = self
- .fs_context
- .unwrap_or_else(|| FsContext::global().clone());
- let signal_list = self.signal_list.unwrap_or_else(|| SignalList::new());
- let set_child_tid = self.set_child_tid.unwrap_or(0);
- signal_list.clear_pending();
- let thread = Arc::new(Thread {
- tid,
- process: process.clone(),
- files,
- fs_context,
- signal_list,
- inner: Spin::new(ThreadInner {
- name,
- tls: self.tls,
- set_child_tid,
- }),
- });
- process_list.add_thread(&thread);
- process.add_thread(&thread, process_list.prove_mut());
- thread
- }
- }
- impl Thread {
- pub fn current<'lt>() -> BorrowedArc<'lt, Self> {
- // SAFETY: We won't change the thread pointer in the current CPU when
- // we return here after some preemption.
- let current: &Option<CurrentThread> = unsafe { CURRENT_THREAD.as_ref() };
- let current = current.as_ref().expect("Current thread is not set");
- // SAFETY: We can only use the returned value when we are in the context of the thread.
- unsafe { BorrowedArc::from_raw(current.thread) }
- }
- pub fn raise(self: &Arc<Self>, signal: Signal) -> RaiseResult {
- self.signal_list.raise(signal)
- }
- /// # Safety
- /// This function is unsafe because it accesses the `current_cpu()`, which needs
- /// to be called in a preemption disabled context.
- pub unsafe fn load_thread_area32(&self) {
- if let Some(tls) = self.inner.lock().tls.as_ref() {
- // SAFETY: Preemption is disabled.
- tls.load(local_cpu());
- }
- }
- pub fn set_thread_area(&self, desc: &mut UserDescriptor) -> KResult<()> {
- let mut inner = self.inner.lock();
- // Clear the TLS area if it is not present.
- if desc.flags.is_read_exec_only() && !desc.flags.is_present() {
- if desc.limit == 0 || desc.base == 0 {
- return Ok(());
- }
- let len = if desc.flags.is_limit_in_pages() {
- (desc.limit as usize) << 12
- } else {
- desc.limit as usize
- };
- CheckedUserPointer::new(desc.base as _, len)?.zero()?;
- return Ok(());
- }
- let (tls, entry) = UserTLS::new32(desc.base, desc.limit, desc.flags.is_limit_in_pages());
- desc.entry = entry;
- inner.tls = Some(tls);
- Ok(())
- }
- pub fn set_name(&self, name: Arc<[u8]>) {
- self.inner.lock().name = name;
- }
- pub fn get_name(&self) -> Arc<[u8]> {
- self.inner.lock().name.clone()
- }
- /// # Safety
- /// This function needs to be called with preempt count == 1.
- /// We won't return so clean all the resources before calling this.
- pub unsafe fn exit() -> ! {
- // SAFETY: We won't change the thread pointer in the current CPU when
- // we return here after some preemption.
- let current: &Option<CurrentThread> = unsafe { CURRENT_THREAD.as_ref() };
- let current = current.as_ref().expect("Current thread is not set");
- // SAFETY: We can only use the `run_context` when we are in the context of the thread.
- let runnable = unsafe { current.runnable.as_ref() };
- runnable.return_context.switch_noreturn()
- }
- }
- impl ThreadRunnable {
- pub fn new(thread: Arc<Thread>, entry: VAddr, stack_pointer: VAddr) -> Self {
- let mut interrupt_context = InterruptContext::default();
- interrupt_context.set_return_address(entry.addr() as _, true);
- interrupt_context.set_stack_pointer(stack_pointer.addr() as _, true);
- interrupt_context.set_interrupt_enabled(true);
- Self {
- thread,
- interrupt_context,
- interrupt_stack_pointer: AtomicUsize::new(0),
- return_context: ExecutionContext::new(),
- }
- }
- pub fn from_context(thread: Arc<Thread>, interrupt_context: InterruptContext) -> Self {
- Self {
- thread,
- interrupt_context,
- interrupt_stack_pointer: AtomicUsize::new(0),
- return_context: ExecutionContext::new(),
- }
- }
- }
- impl Contexted for ThreadRunnable {
- fn load_running_context(&self) {
- let thread: &Thread = &self.thread;
- match self.interrupt_stack_pointer.load(Ordering::Relaxed) {
- 0 => {}
- sp => unsafe {
- // SAFETY: Preemption is disabled.
- arch::load_interrupt_stack(local_cpu(), sp as u64);
- },
- }
- // SAFETY: Preemption is disabled.
- unsafe {
- // SAFETY: `self` and `thread` are valid and non-null.
- let current_thread = CurrentThread {
- thread: NonNull::new_unchecked(thread as *const _ as *mut _),
- runnable: NonNull::new_unchecked(self as *const _ as *mut _),
- };
- // SAFETY: Preemption is disabled.
- CURRENT_THREAD.swap(Some(current_thread));
- }
- thread.process.mm_list.activate();
- unsafe {
- // SAFETY: Preemption is disabled.
- thread.load_thread_area32();
- }
- }
- fn restore_running_context(&self) {
- self.thread.process.mm_list.deactivate();
- }
- }
- impl Run for ThreadRunnable {
- type Output = ();
- fn run(self: Pin<&mut Self>, _waker: &Waker) -> RunState<Self::Output> {
- let mut task_context = ExecutionContext::new();
- task_context.set_interrupt(false);
- task_context.set_ip(_arch_fork_return as _);
- task_context.set_sp(&self.interrupt_context as *const _ as _);
- eonix_preempt::disable();
- // TODO!!!!!: CHANGE THIS
- let sp = unsafe {
- let mut sp: usize;
- asm!(
- "mov %rsp, {0}",
- out(reg) sp,
- options(nomem, preserves_flags, att_syntax),
- );
- sp -= 512;
- sp &= !0xf;
- sp
- };
- self.interrupt_stack_pointer.store(sp, Ordering::Relaxed);
- unsafe {
- // SAFETY: Preemption is disabled.
- arch::load_interrupt_stack(local_cpu(), sp as u64);
- }
- eonix_preempt::enable();
- self.return_context.switch_to(&task_context);
- // We return here with preempt count == 1.
- eonix_preempt::enable();
- RunState::Finished(())
- }
- }
|