2024-06-21 10:57:08 +08:00

155 lines
3.8 KiB
Rust

// SPDX-License-Identifier: MPL-2.0
//! The std library of Asterinas.
#![no_std]
#![deny(unsafe_code)]
#![allow(incomplete_features)]
#![feature(btree_cursors)]
#![feature(btree_extract_if)]
#![feature(const_option)]
#![feature(extend_one)]
#![feature(fn_traits)]
#![feature(format_args_nl)]
#![feature(int_roundings)]
#![feature(let_chains)]
#![feature(linked_list_remove)]
#![feature(register_tool)]
// FIXME: This feature is used to support vm capbility now as a work around.
// Since this is an incomplete feature, use this feature is unsafe.
// We should find a proper method to replace this feature with min_specialization, which is a sound feature.
#![feature(specialization)]
#![feature(step_trait)]
#![feature(trait_alias)]
#![feature(trait_upcasting)]
#![register_tool(component_access_control)]
use aster_frame::{
arch::qemu::{exit_qemu, QemuExitCode},
boot,
};
use process::Process;
use crate::{
prelude::*,
thread::{
kernel_thread::{KernelThreadExt, ThreadOptions},
Thread,
},
};
extern crate alloc;
extern crate lru;
#[macro_use]
extern crate controlled;
#[cfg(ktest)]
#[macro_use]
extern crate ktest;
#[macro_use]
extern crate getset;
pub mod arch;
pub mod console;
pub mod cpu;
pub mod device;
pub mod driver;
pub mod error;
pub mod events;
pub mod fs;
pub mod net;
pub mod prelude;
mod process;
mod sched;
pub mod softirq_id;
pub mod syscall;
mod taskless;
pub mod thread;
pub mod time;
mod util;
pub(crate) mod vdso;
pub mod vm;
pub fn init() {
util::random::init();
driver::init();
time::init();
net::init();
sched::init();
fs::rootfs::init(boot::initramfs()).unwrap();
device::init().unwrap();
vdso::init();
taskless::init();
process::init();
}
fn init_thread() {
println!(
"[kernel] Spawn init thread, tid = {}",
current_thread!().tid()
);
// Work queue should be initialized before interrupt is enabled,
// in case any irq handler uses work queue as bottom half
thread::work_queue::init();
// FIXME: Remove this if we move the step of mounting
// the filesystems to be done within the init process.
aster_frame::trap::enable_local();
net::lazy_init();
fs::lazy_init();
// driver::pci::virtio::block::block_device_test();
let thread = Thread::spawn_kernel_thread(ThreadOptions::new(|| {
println!("[kernel] Hello world from kernel!");
let current = current_thread!();
let tid = current.tid();
debug!("current tid = {}", tid);
}));
thread.join();
info!(
"[aster-nix/lib.rs] spawn kernel thread, tid = {}",
thread.tid()
);
print_banner();
let karg = boot::kernel_cmdline();
let initproc = Process::spawn_user_process(
karg.get_initproc_path().unwrap(),
karg.get_initproc_argv().to_vec(),
karg.get_initproc_envp().to_vec(),
)
.expect("Run init process failed.");
// Wait till initproc become zombie.
while !initproc.is_zombie() {
// We don't have preemptive scheduler now.
// The long running init thread should yield its own execution to allow other tasks to go on.
Thread::yield_now();
}
// TODO: exit via qemu isa debug device should not be the only way.
let exit_code = if initproc.exit_code().unwrap() == 0 {
QemuExitCode::Success
} else {
QemuExitCode::Failed
};
exit_qemu(exit_code);
}
/// first process never return
#[controlled]
pub fn run_first_process() -> ! {
Thread::spawn_kernel_thread(ThreadOptions::new(init_thread));
unreachable!()
}
fn print_banner() {
println!("\x1B[36m");
println!(
r"
_ ___ _____ ___ ___ ___ _ _ _ ___
/_\ / __|_ _| __| _ \_ _| \| | /_\ / __|
/ _ \\__ \ | | | _|| /| || .` |/ _ \\__ \
/_/ \_\___/ |_| |___|_|_\___|_|\_/_/ \_\___/
"
);
println!("\x1B[0m");
}