diff --git a/Cargo.lock b/Cargo.lock index 98f8dfed..25d41c01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2115,7 +2115,6 @@ dependencies = [ "atomic_enum", "bitflags 2.4.2", "bytemuck", - "cfg-if", "crossbeam-queue", "device-api", "device-api-macros", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 7f985589..b0a8611f 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -40,7 +40,6 @@ bitflags = "2.3.3" spinning_top = "0.2.5" static_assertions = "1.1.0" tock-registers = "0.8.1" -cfg-if = "1.0.0" git-version = "0.3.5" log = "0.4.20" futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } @@ -70,6 +69,12 @@ kernel-arch-x86_64 = { path = "arch/x86_64" } prettyplease = "0.2.15" abi-generator = { path = "../tool/abi-generator" } +# To make rust-analyzer recognize those +[dev-dependencies] +aarch64-cpu = "9.3.1" +device-tree = { path = "lib/device-tree" } +kernel-arch-aarch64 = { path = "arch/aarch64" } + [features] default = ["fb_console"] fb_console = [] diff --git a/kernel/libk/src/module.rs b/kernel/libk/src/module.rs index 4551d5bf..c6351ee1 100644 --- a/kernel/libk/src/module.rs +++ b/kernel/libk/src/module.rs @@ -128,7 +128,7 @@ pub fn load(file: FileRef) -> Result { let name = dynstr.get(sym.st_name as _).unwrap(); if sym.st_shndx == elf::abi::SHN_UNDEF && sym.st_bind() != elf::abi::STB_LOCAL { - let Some(value) = lookup_symbol(&name) else { + let Some(value) = lookup_symbol(name) else { log::warn!("Could not load module: undefined reference to {:?} (possibly compiled against a different libk?)", name); return Err(Error::InvalidArgument); }; diff --git a/kernel/libk/src/task/binary/elf.rs b/kernel/libk/src/task/binary/elf.rs index 1e429585..9ba1f522 100644 --- a/kernel/libk/src/task/binary/elf.rs +++ b/kernel/libk/src/task/binary/elf.rs @@ -132,6 +132,7 @@ pub fn open_elf_file(file: Arc) -> Result, Error> } } +#[allow(clippy::type_complexity)] pub fn open_elf_direct( file: Arc, ) -> Result<(ElfStream>>, FileReader>), Error> { diff --git a/kernel/libk/src/task/process.rs b/kernel/libk/src/task/process.rs index 9597859e..978f2155 100644 --- a/kernel/libk/src/task/process.rs +++ b/kernel/libk/src/task/process.rs @@ -7,10 +7,13 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; -use kernel_arch::KernelTableManagerImpl; +use kernel_arch::{ + task::{TaskContext, UserContextInfo}, + KernelTableManagerImpl, +}; use libk_mm::{phys::GlobalPhysicalAllocator, process::ProcessAddressSpace}; use libk_util::{ - event::OneTimeEvent, + event::{BoolEvent, OneTimeEvent}, sync::{ spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard}, IrqSafeSpinlock, @@ -23,6 +26,7 @@ use yggdrasil_abi::{ use crate::{ task::{ + binary, futex::UserspaceMutex, thread::Thread, types::{AllocateProcessId, ProcessTlsInfo}, @@ -62,6 +66,8 @@ pub struct ProcessInner { mutexes: BTreeMap>, space: Option>, image: Option, + + thread_exits: BTreeMap>, } /// Describes a process within the system @@ -106,7 +112,7 @@ impl Process { // Create "main" thread let thread = Thread::new_uthread(process.id, space, context); - process.inner.write().threads.push(thread.clone()); + process.inner.write().register_thread(thread.clone()); MANAGER.register_process(process.clone()); @@ -123,33 +129,33 @@ impl Process { /// Spawns a new child thread within the process pub fn spawn_thread(self: &Arc, options: &ThreadSpawnOptions) -> Result { log::debug!("Spawn thread in {} with options: {:#x?}", self.id, options); - // let mut inner = self.inner.write(); + let mut inner = self.inner.write(); - // let space = inner.space.clone().unwrap(); + let space = inner.space.clone().unwrap(); - todo!() - // XXX - // let tls_address = if let Some(image) = inner.image.as_ref() { - // proc::elf::clone_tls(&space, image)? - // } else { - // 0 - // }; + let tls_address = if let Some(image) = inner.image.as_ref() { + binary::elf::clone_tls(&space, image)? + } else { + 0 + }; - // let context = TaskContextImpl::user( - // options.entry as _, - // options.argument as _, - // space.as_address_with_asid(), - // options.stack_top, - // tls_address, - // )?; - // let thread = Thread::new_uthread(self.clone(), space.clone(), context); - // let id = thread.id; + let info = UserContextInfo { + entry: options.entry as _, + argument: options.argument as _, + address_space: space.as_address_with_asid(), + stack_pointer: options.stack_top, + single_step: false, + tls: tls_address, + }; + let context = TaskContextImpl::user(info)?; + let thread = Thread::new_uthread(self.id, space.clone(), context); + let id = thread.id; - // inner.add_thread(thread.clone()); + inner.register_thread(thread.clone()); - // thread.enqueue(); + thread.enqueue(); - // Ok(id) + Ok(id) } unsafe fn fork_inner>( @@ -367,6 +373,20 @@ impl Process { } } + pub async fn wait_for_thread(&self, thread: ThreadId) -> Result<(), Error> { + let exit = { + let inner = self.inner.read(); + inner + .thread_exits + .get(&thread) + .cloned() + .ok_or(Error::DoesNotExist)? + }; + + exit.wait().await; + Ok(()) + } + pub async fn terminate_others(&self, except: ThreadId) { let mut inner = self.inner.write(); @@ -399,10 +419,13 @@ impl ProcessInner { mutexes: BTreeMap::new(), image, space: space.clone(), + + thread_exits: BTreeMap::new(), } } - pub fn add_thread(&mut self, thread: Arc) { + pub fn register_thread(&mut self, thread: Arc) { + self.thread_exits.insert(thread.id, thread.exit.clone()); self.threads.push(thread); } diff --git a/kernel/libk/src/task/thread.rs b/kernel/libk/src/task/thread.rs index a31f1634..6a5543e5 100644 --- a/kernel/libk/src/task/thread.rs +++ b/kernel/libk/src/task/thread.rs @@ -75,7 +75,8 @@ pub struct Thread { inner: IrqSafeSpinlock, signal_queue: SegQueue, - pub exit: BoolEvent, + pub exit: Arc, + /// CPU scheduling affinity mask pub affinity: ThreadAffinity, } @@ -125,7 +126,7 @@ impl Thread { inner: IrqSafeSpinlock::new(ThreadInner { signal_entry: None }), signal_queue: SegQueue::new(), - exit: BoolEvent::new(), + exit: Arc::new(BoolEvent::new()), affinity: ThreadAffinity::any_cpu(), }); diff --git a/kernel/src/arch/aarch64/timer.rs b/kernel/src/arch/aarch64/timer.rs index dce8daed..cd6d8c56 100644 --- a/kernel/src/arch/aarch64/timer.rs +++ b/kernel/src/arch/aarch64/timer.rs @@ -25,7 +25,7 @@ pub struct ArmTimer { } /// ARM timer tick interval (in some time units?) -pub const TICK_INTERVAL: u64 = 1000000; +pub const TICK_INTERVAL: u64 = 250000; impl InterruptHandler for ArmTimer { fn handle_irq(&self, _vector: Option) -> bool { @@ -76,36 +76,6 @@ impl Device for ArmTimer { } } -// impl TimestampSource for ArmTimer { -// fn timestamp(&self) -> Result { -// } -// } - -// impl InterruptSource for ArmTimer { -// fn handle_irq(&self) -> Result { -// CNTP_TVAL_EL0.set(TICK_INTERVAL); -// let t = self.timestamp()?; -// -// wait::tick(t); -// tasklet::tick(t); -// -// unsafe { -// Cpu::local().queue().yield_cpu(); -// } -// -// Ok(true) -// } -// -// unsafe fn init_irq(&'static self) -> Result<(), Error> { -// let intc = PLATFORM.interrupt_controller(); -// -// intc.register_handler(self.irq, self)?; -// intc.enable_irq(self.irq)?; -// -// Ok(()) -// } -// } - impl ArmTimer { /// Constructs an instance of ARM generic timer. /// diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index c742d66b..4f37a5ac 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -2,7 +2,6 @@ use abi::error::Error; -use cfg_if::cfg_if; use device_api::{ interrupt::{IpiDeliveryTarget, IpiMessage}, ResetDevice, @@ -10,19 +9,18 @@ use device_api::{ use kernel_arch::{Architecture, ArchitectureImpl}; use libk_mm::table::EntryLevel; -cfg_if! { - if #[cfg(target_arch = "aarch64")] { - pub mod aarch64; +#[cfg(any(target_arch = "aarch64", rust_analyzer))] +pub mod aarch64; +#[cfg(any(target_arch = "aarch64", rust_analyzer))] +pub use aarch64::{AArch64 as PlatformImpl, PLATFORM}; - pub use aarch64::{AArch64 as PlatformImpl, PLATFORM}; - } else if #[cfg(target_arch = "x86_64")] { - pub mod x86_64; +#[cfg(any(target_arch = "x86_64", rust_analyzer))] +pub mod x86_64; +#[cfg(any(target_arch = "x86_64", rust_analyzer))] +pub use x86_64::{PLATFORM, X86_64 as PlatformImpl}; - pub use x86_64::{X86_64 as PlatformImpl, PLATFORM}; - } else { - compile_error!("Architecture is not supported"); - } -} +#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] +compile_error!("Unsupported architecture"); /// Architecture-specific lowest level of page mapping pub type L3 = ::L3; diff --git a/kernel/src/device/power/mod.rs b/kernel/src/device/power/mod.rs index 8b996e54..b82f1c44 100644 --- a/kernel/src/device/power/mod.rs +++ b/kernel/src/device/power/mod.rs @@ -1,10 +1,4 @@ //! Power-management related device drivers -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(target_arch = "aarch64")] { - pub mod arm_psci; - // pub mod sunxi_rwdog; - } -} +#[cfg(any(target_arch = "aarch64", rust_analyzer))] +pub mod arm_psci; diff --git a/kernel/src/device/serial/mod.rs b/kernel/src/device/serial/mod.rs index 4a364aa0..1388fa87 100644 --- a/kernel/src/device/serial/mod.rs +++ b/kernel/src/device/serial/mod.rs @@ -1,10 +1,4 @@ //! Serial device interfaces -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(target_arch = "aarch64")] { - pub mod pl011; - // pub mod sunxi_uart; - } -} +#[cfg(any(target_arch = "aarch64", rust_analyzer))] +pub mod pl011; diff --git a/kernel/src/device/serial/pl011.rs b/kernel/src/device/serial/pl011.rs index f4495f04..e05fefce 100644 --- a/kernel/src/device/serial/pl011.rs +++ b/kernel/src/device/serial/pl011.rs @@ -219,7 +219,7 @@ impl Device for Pl011 { self.inner.init(IrqSafeSpinlock::new(inner)); - debug::add_sink(self, LogLevel::Info); + debug::add_sink(self, LogLevel::Debug); devfs::add_char_device(self, CharDeviceType::TtySerial)?; Ok(()) diff --git a/kernel/src/fs/sysfs.rs b/kernel/src/fs/sysfs.rs index f655ff9d..f040c082 100644 --- a/kernel/src/fs/sysfs.rs +++ b/kernel/src/fs/sysfs.rs @@ -2,14 +2,14 @@ use core::sync::atomic::Ordering; -use abi::{error::Error, io::OpenOptions}; -use alloc::{format, string::String, sync::Arc}; +use abi::error::Error; +use alloc::{format, string::String}; use git_version::git_version; use libk::{ - task::{cpu_count, process::Process, sched}, + task::{cpu_count, sched}, vfs::{ impls::{const_value_node, mdir, read_fn_node, ReadOnlyFnValueNode}, - CommonImpl, InstanceData, NodeRef, RegularImpl, + NodeRef, }, }; use libk_mm::phys; diff --git a/kernel/src/syscall/imp/sys_process.rs b/kernel/src/syscall/imp/sys_process.rs index 3f0c8b2a..d818325a 100644 --- a/kernel/src/syscall/imp/sys_process.rs +++ b/kernel/src/syscall/imp/sys_process.rs @@ -6,12 +6,13 @@ use abi::{ mem::MappingSource, process::{ ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnOption, SpawnOptions, + ThreadSpawnOptions, }, }; use alloc::sync::Arc; use libk::{ block, - task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread}, + task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread, ThreadId}, vfs::IoContext, }; use libk_mm::{ @@ -236,3 +237,28 @@ pub(crate) fn start_session() -> Result<(), Error> { Ok(()) } + +pub(crate) fn spawn_thread(options: &ThreadSpawnOptions) -> Result { + let thread = Thread::current(); + let process = thread.process(); + + process + .spawn_thread(options) + .map(|tid| tid.as_user() as u32) +} + +pub(crate) fn exit_thread() -> ! { + let thread = Thread::current(); + // TODO exit codes are not supported in here + thread.exit(ExitCode::SUCCESS) +} + +pub(crate) fn wait_thread(id: u32) -> Result<(), Error> { + let tid = ThreadId::User(id as u64); + let this_thread = Thread::current(); + let process = this_thread.process(); + + block!(process.wait_for_thread(tid).await)??; + + Ok(()) +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index f4450d2f..93c3a6df 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -39,7 +39,7 @@ mod generated { use abi::{ io::ChannelPublisherId, - process::{ExecveOptions, ProcessId}, + process::{ExecveOptions, ProcessId, ThreadSpawnOptions}, SyscallFunction, }; use abi_lib::SyscallRegister; diff --git a/lib/abi/def/yggdrasil.abi b/lib/abi/def/yggdrasil.abi index 4ad39c16..b09668eb 100644 --- a/lib/abi/def/yggdrasil.abi +++ b/lib/abi/def/yggdrasil.abi @@ -63,6 +63,11 @@ syscall spawn_process(options: &SpawnOptions<'_>) -> Result; syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>; syscall get_pid() -> ProcessId; +// TODO use ThreadId +syscall spawn_thread(options: &ThreadSpawnOptions) -> Result; +syscall exit_thread() -> !; +syscall wait_thread(tid: u32) -> Result<()>; + syscall nanosleep(dur: &Duration) -> Result<()>; syscall exit_signal(frame: &SignalEntryData) -> !; diff --git a/lib/runtime/src/sys/mod.rs b/lib/runtime/src/sys/mod.rs index 8efd3952..b9a9f0cf 100644 --- a/lib/runtime/src/sys/mod.rs +++ b/lib/runtime/src/sys/mod.rs @@ -20,6 +20,7 @@ mod generated { net::SocketType, process::{ ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions, + ThreadSpawnOptions, }, SyscallFunction, };