#![no_std] #![no_main] #![feature(c_size_t)] #![feature(concat_idents)] #![feature(arbitrary_self_types)] #![feature(get_mut_unchecked)] #![feature(macro_metavar_expr)] #![feature(naked_functions)] extern crate alloc; #[allow(warnings)] mod bindings; mod driver; mod elf; mod fs; mod hash; mod intrusive_list; mod io; mod kernel; mod net; mod path; mod prelude; mod rcu; mod sync; use alloc::{ffi::CString, sync::Arc}; use core::alloc::{GlobalAlloc, Layout}; use elf::ParsedElf32; use eonix_mm::{address::PAddr, paging::PFN}; use eonix_runtime::{run::FutureRun, scheduler::Scheduler, task::Task}; use kernel::{ cpu::init_localcpu, mem::Page, task::{KernelStack, ProcessBuilder, ProcessList, ThreadBuilder, ThreadRunnable}, vfs::{ dentry::Dentry, mount::{do_mount, MS_NOATIME, MS_NODEV, MS_NOSUID, MS_RDONLY}, FsContext, }, CharDevice, }; 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()); arch::freeze() } extern "C" { fn _do_allocate(size: usize) -> *mut core::ffi::c_void; fn _do_deallocate(ptr: *mut core::ffi::c_void, size: core::ffi::c_size_t) -> i32; fn init_pci(); } struct Allocator; unsafe impl GlobalAlloc for Allocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let result = _do_allocate(layout.size()); if result.is_null() { core::ptr::null_mut() } else { result as *mut u8 } } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { match _do_deallocate(ptr as *mut core::ffi::c_void, layout.size()) { 0 => (), _ => panic!("Failed to deallocate memory"), } } } #[global_allocator] static ALLOCATOR: Allocator = Allocator; extern "C" { fn init_allocator(); } #[no_mangle] pub extern "C" fn rust_kinit(early_kstack_paddr: PAddr) -> ! { // We don't call global constructors. // Rust doesn't need that, and we're not going to use global variables in C++. init_localcpu(); unsafe { init_allocator() }; kernel::interrupt::init().unwrap(); // TODO: Move this to rust. unsafe { init_pci() }; // 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(PFN::from(early_kstack_paddr)))); unsafe { // SAFETY: `preempt::count()` == 1. Scheduler::goto_scheduler_noreturn() } } async fn init_process(early_kstack_pfn: PFN) { unsafe { Page::from_raw(early_kstack_pfn) }; kernel::syscall::register_syscalls(); CharDevice::init().unwrap(); // We might want the serial initialized as soon as possible. driver::serial::init().unwrap(); driver::e1000e::register_e1000e_driver(); driver::ahci::register_ahci_driver(); fs::tmpfs::init(); fs::procfs::init(); fs::fat32::init(); kernel::smp::bootstrap_smp(); let (ip, sp, mm_list) = { // 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 = Dentry::open(fs_context, Path::new(b"/mnt/busybox").unwrap(), true) .expect("busybox should be present in /mnt"); let argv = vec![ CString::new("/mnt/busybox").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(), ]; let elf = ParsedElf32::parse(init.clone()).unwrap(); elf.load(argv, envp).unwrap() }; let thread_builder = ThreadBuilder::new().name(Arc::from(*b"busybox")); let mut process_list = Task::block_on(ProcessList::get().write()); let (thread, process) = ProcessBuilder::new() .mm_list(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::(ThreadRunnable::new(thread, ip, sp)); }