#![no_std] #![no_main] #![feature(c_size_t)] #![feature(concat_idents)] #![feature(arbitrary_self_types)] #![feature(get_mut_unchecked)] #![feature(macro_metavar_expr)] extern crate alloc; mod driver; mod fs; mod hash; mod io; mod kernel; mod kernel_init; mod net; mod path; mod prelude; mod rcu; mod sync; use crate::kernel::task::alloc_pid; use alloc::{ffi::CString, sync::Arc}; use core::{ hint::spin_loop, sync::atomic::{AtomicBool, Ordering}, }; use eonix_hal::{processor::CPU, traits::trap::IrqState, trap::disable_irqs_save}; use eonix_mm::address::PRange; use eonix_runtime::{run::FutureRun, scheduler::Scheduler, task::Task}; use kernel::{ mem::GlobalPageAlloc, task::{ new_thread_runnable, KernelStack, ProcessBuilder, ProcessList, ProgramLoader, ThreadBuilder, }, vfs::{ dentry::Dentry, mount::{do_mount, MS_NOATIME, MS_NODEV, MS_NOSUID, MS_RDONLY}, FsContext, }, CharDevice, }; use kernel_init::setup_memory; use path::Path; use prelude::*; #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { if let Some(location) = info.location() { println_fatal!( "panicked at {}:{}:{}", location.file(), location.line(), location.column() ); } else { println_fatal!("panicked at "); } println_fatal!(); println_fatal!("{}", info.message()); loop {} } static BSP_OK: AtomicBool = AtomicBool::new(false); #[eonix_hal::main] fn kernel_init(mut data: eonix_hal::bootstrap::BootStrapData) -> ! { setup_memory(&mut data); BSP_OK.store(true, Ordering::Release); #[cfg(target_arch = "riscv64")] { driver::sbi_console::init_console(); } kernel::pcie::init_pcie().expect("Unable to initialize PCIe bus"); // To satisfy the `Scheduler` "preempt count == 0" assertion. eonix_preempt::disable(); // We need root dentry to be present in constructor of `FsContext`. // So call `init_vfs` first, then `init_multitasking`. Scheduler::init_local_scheduler::(); Scheduler::get().spawn::(FutureRun::new(init_process(data.get_early_stack()))); drop(data); unsafe { // SAFETY: `preempt::count()` == 1. Scheduler::goto_scheduler_noreturn() } } #[eonix_hal::ap_main] fn kernel_ap_main(_stack_range: PRange) -> ! { while BSP_OK.load(Ordering::Acquire) == false { // Wait for BSP to finish initializing. spin_loop(); } Scheduler::init_local_scheduler::(); println_debug!("AP{} started", CPU::local().cpuid()); eonix_preempt::disable(); // TODO!!!!!: Free the stack after having switched to idle task. unsafe { // SAFETY: `preempt::count()` == 1. Scheduler::goto_scheduler_noreturn() } } async fn init_process(early_kstack: PRange) { unsafe { let irq_ctx = disable_irqs_save(); // SAFETY: IRQ is disabled. GlobalPageAlloc::add_pages(early_kstack); irq_ctx.restore(); } CharDevice::init().unwrap(); #[cfg(target_arch = "x86_64")] { // We might want the serial initialized as soon as possible. driver::serial::init().unwrap(); driver::e1000e::register_e1000e_driver(); driver::ahci::register_ahci_driver(); } #[cfg(target_arch = "riscv64")] { driver::serial::init().unwrap(); driver::virtio::init_virtio_devices(); driver::e1000e::register_e1000e_driver(); driver::ahci::register_ahci_driver(); driver::goldfish_rtc::probe(); } fs::tmpfs::init(); fs::procfs::init(); fs::fat32::init(); fs::ext4::init(); let load_info = { // mount fat32 /mnt directory let fs_context = FsContext::global(); let mnt_dir = Dentry::open(fs_context, Path::new(b"/mnt/").unwrap(), true).unwrap(); mnt_dir.mkdir(0o755).unwrap(); do_mount( &mnt_dir, "/dev/sda", "/mnt", "fat32", MS_RDONLY | MS_NOATIME | MS_NODEV | MS_NOSUID, ) .unwrap(); let init_names = [ &b"/sbin/init"[..], &b"/init"[..], &b"/bin/busybox"[..], &b"/mnt/busybox"[..], ]; let mut init_name = None; let mut init = None; for name in &init_names { if let Ok(dentry) = Dentry::open(fs_context, Path::new(name).unwrap(), true) { if dentry.is_valid() { init_name = Some(*name); init = Some(dentry); break; } } } let init = init.expect("No init binary found in the system."); let init_name = init_name.unwrap(); let argv = vec![ CString::new(init_name).unwrap(), CString::new("sh").unwrap(), CString::new("/mnt/initsh").unwrap(), ]; let envp = vec![ CString::new("LANG=C").unwrap(), CString::new("HOME=/root").unwrap(), CString::new("PATH=/mnt").unwrap(), CString::new("PWD=/").unwrap(), ]; ProgramLoader::parse(init.clone()) .unwrap() .load(argv, envp) .unwrap() }; let thread_builder = ThreadBuilder::new() .name(Arc::from(&b"busybox"[..])) .entry(load_info.entry_ip, load_info.sp); let mut process_list = Task::block_on(ProcessList::get().write()); let (thread, process) = ProcessBuilder::new() .pid(alloc_pid()) .mm_list(load_info.mm_list) .thread_builder(thread_builder) .build(&mut process_list); process_list.set_init_process(process); // TODO!!!: Remove this. thread.files.open_console(); Scheduler::get().spawn::(new_thread_runnable(thread)); }