//! osdev-x kernel crate #![feature( if_let_guard, step_trait, decl_macro, optimize_attribute, const_trait_impl, maybe_uninit_slice, arbitrary_self_types, let_chains, linked_list_cursors, rustc_private, allocator_api, trait_alias, slice_ptr_get, slice_split_once, iter_collect_into, iter_next_chunk, exact_size_is_empty, never_type, format_args_nl, associated_type_defaults )] #![allow( clippy::new_without_default, clippy::fn_to_numeric_cast, clippy::match_ref_pats, clippy::match_single_binding, clippy::missing_transmute_annotations, clippy::modulo_one, async_fn_in_trait )] #![deny(missing_docs)] #![no_std] #![no_main] use abi::{error::Error, io::FileMode}; use alloc::string::String; use git_version::git_version; use kernel_arch::{Architecture, ArchitectureImpl}; use libk::{ arch::Cpu, debug, fs::{ devfs, sysfs::{ self, attribute::{StringAttribute, StringAttributeOps}, }, }, }; use libk_util::sync::SpinFence; use crate::{ arch::{Platform, PLATFORM}, task::spawn_kernel_closure, }; extern crate yggdrasil_abi as abi; extern crate alloc; #[cfg(not(rust_analyzer))] extern crate compiler_builtins; extern crate ygg_driver_ahci; extern crate ygg_driver_net_rtl81xx; extern crate ygg_driver_nvme; extern crate ygg_driver_usb_xhci; extern crate ygg_driver_virtio_blk; extern crate ygg_driver_virtio_gpu; extern crate ygg_driver_virtio_net; cfg_if::cfg_if! { if #[cfg(target_arch = "x86_64")] { extern crate ygg_driver_net_igbe; } else if #[cfg(target_arch = "aarch64")] { extern crate ygg_driver_bsp_arm; extern crate ygg_driver_bsp_bcm283x; } else if #[cfg(target_arch = "riscv64")] { extern crate ygg_driver_bsp_riscv; extern crate ygg_driver_bsp_jh7110; extern crate ygg_driver_net_stmmac; } } pub mod arch; pub mod device; pub mod fs; pub mod init; pub mod mem; pub mod panic; pub mod proc; pub mod syscall; pub mod task; pub mod util; static CPU_INIT_FENCE: SpinFence = SpinFence::new(); /// Common kernel main function for application processors pub fn kernel_secondary_main() -> ! { // Synchronize the CPUs to this point CPU_INIT_FENCE.signal(); CPU_INIT_FENCE.wait_all(ArchitectureImpl::cpu_count()); unsafe { task::enter(); } } fn register_sysfs_attributes() { struct Version; struct Arch; impl StringAttributeOps for Version { const NAME: &'static str = "version"; fn read(_state: &Self::Data) -> Result { Ok(git_version!().into()) } } impl StringAttributeOps for Arch { const NAME: &'static str = "arch"; fn read(_state: &Self::Data) -> Result { Ok(util::arch_str().into()) } } let kernel = sysfs::kernel().unwrap(); let kernel_node = kernel.node(); kernel.add_attribute(StringAttribute::from(Version)).ok(); kernel.add_attribute(StringAttribute::from(Arch)).ok(); debug::add_kernel_log_file(kernel_node); } /// Common kernel main function. Must be called for BSP processor only. /// /// # Prerequisites /// /// Before the function can be called, the following preparations must be made: /// /// * Virtual memory set up according to the architecture's memory map /// * Physical memory /// * Heap /// * Basic debugging facilities /// * Initrd #[inline(never)] pub fn kernel_main() -> ! { log::info!( "Yggdrasil v{} ({})", env!("CARGO_PKG_VERSION"), git_version!() ); libk::panic::set_handler(panic::panic_handler); unsafe { PLATFORM.start_application_processors(); } Cpu::init_ipi_queues(ArchitectureImpl::cpu_count()); // Setup the sysfs register_sysfs_attributes(); fs::add_pseudo_devices().unwrap(); // Wait until all APs initialize CPU_INIT_FENCE.signal(); CPU_INIT_FENCE.wait_all(ArchitectureImpl::cpu_count()); // Add keyboard device if let Err(error) = devfs::add_named_char_device(ygg_driver_input::setup(), "kbd", FileMode::new(0o660)) { log::error!("Couldn't add keyboard device: {error:?}"); } task::init().expect("Failed to initialize the scheduler"); spawn_kernel_closure("[kinit]", init::kinit).expect("Could not spawn [kinit]"); log::info!("All cpus ready"); unsafe { task::enter(); } }