mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-01-31 09:31:58 -05:00
This commit refactors the core process representation to decouple
"Identity/Resources" from "Execution/Scheduling". Previously, a
monolithic `Task` struct wrapped in `Arc<SpinLock<>>` caused lock
contention during hot scheduling paths and conflated shared state with
CPU-local state.
The `Task` struct has been split into:
1. `Task` (Shared): Holds process-wide resources (VM, FileTable,
Credentials). Managed via `Arc` and internal fine-grained locking.
2. `OwnedTask` (Private): Holds execution state (Context, v_runtime,
signal mask). Strictly owned by a specific CPU (via the Scheduler) and
accessed lock-free.
Key changes:
* Scheduler:
chedState` now owns tasks via `Box<OwnedTask>`.
- Transitions between `run_queue` and `running_task` involve strictly
moving ownership of the Box, ensuring pointer stability.
- The EEVDF comparison logic now explicitly handles comparisons
between the queued candidates and the currently running task (which is
not in the queue).
* Current Task Access:
- `current()` now returns a `CurrentTaskGuard` which:
1. Disables preemption (preventing context switches while holding
the reference).
2. Performs a runtime borrow check (panic on double-mutable borrow).
3. Dereferences a cached Per-CPU raw pointer for O(1) access.
219 lines
5.8 KiB
Rust
219 lines
5.8 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
#![feature(used_with_arg)]
|
|
#![feature(likely_unlikely)]
|
|
#![feature(box_as_ptr)]
|
|
|
|
use alloc::{
|
|
boxed::Box,
|
|
string::{String, ToString},
|
|
vec,
|
|
vec::Vec,
|
|
};
|
|
use arch::{Arch, ArchImpl};
|
|
use core::panic::PanicInfo;
|
|
use drivers::{fdt_prober::get_fdt, fs::register_fs_drivers};
|
|
use fs::VFS;
|
|
use getargs::{Opt, Options};
|
|
use libkernel::{
|
|
CpuOps, VirtualMemory,
|
|
fs::{
|
|
BlockDevice, OpenFlags, attr::FilePermissions, blk::ramdisk::RamdiskBlkDev, path::Path,
|
|
pathbuf::PathBuf,
|
|
},
|
|
memory::{
|
|
address::{PA, VA},
|
|
region::PhysMemoryRegion,
|
|
},
|
|
};
|
|
use log::{error, warn};
|
|
use process::ctx::UserCtx;
|
|
use sched::{
|
|
current::current_task_shared, sched_init, spawn_kernel_work, uspc_ret::dispatch_userspace_task,
|
|
};
|
|
|
|
extern crate alloc;
|
|
|
|
mod arch;
|
|
mod clock;
|
|
mod console;
|
|
mod drivers;
|
|
mod fs;
|
|
mod interrupts;
|
|
mod kernel;
|
|
mod memory;
|
|
mod process;
|
|
mod sched;
|
|
mod sync;
|
|
|
|
#[panic_handler]
|
|
fn on_panic(info: &PanicInfo) -> ! {
|
|
ArchImpl::disable_interrupts();
|
|
|
|
let panic_msg = info.message();
|
|
|
|
if let Some(location) = info.location() {
|
|
error!(
|
|
"Kernel panicked at {}:{}:{}: {}",
|
|
location.file(),
|
|
location.line(),
|
|
location.column(),
|
|
panic_msg
|
|
);
|
|
} else {
|
|
error!("Kernel panicked at unknown location: {panic_msg}");
|
|
}
|
|
|
|
ArchImpl::power_off();
|
|
}
|
|
|
|
async fn launch_init(opts: KOptions) {
|
|
let init = opts
|
|
.init
|
|
.unwrap_or_else(|| panic!("No init specified in kernel command line"));
|
|
|
|
let dt = get_fdt();
|
|
|
|
let initrd_block_dev: Option<Box<dyn BlockDevice>> = if let Some(chosen) =
|
|
dt.find_nodes("/chosen").next()
|
|
&& let Some(start_addr) = chosen
|
|
.find_property("linux,initrd-start")
|
|
.map(|prop| prop.u64())
|
|
&& let Some(end_addr) = chosen
|
|
.find_property("linux,initrd-end")
|
|
.map(|prop| prop.u64())
|
|
{
|
|
let region = PhysMemoryRegion::from_start_end_address(
|
|
PA::from_value(start_addr as _),
|
|
PA::from_value(end_addr as _),
|
|
);
|
|
|
|
Some(Box::new(
|
|
RamdiskBlkDev::new(
|
|
region,
|
|
VA::from_value(0xffff_9800_0000_0000),
|
|
&mut *ArchImpl::kern_address_space().lock_save_irq(),
|
|
)
|
|
.unwrap(),
|
|
))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let root_fs = opts
|
|
.root_fs
|
|
.unwrap_or_else(|| panic!("No root FS driver specified in kernel command line"));
|
|
|
|
VFS.mount_root(&root_fs, initrd_block_dev)
|
|
.await
|
|
.unwrap_or_else(|e| panic!("Failed to mount root FS: {}", e));
|
|
|
|
// Process all automounts.
|
|
for (path, fs) in opts.automounts.iter() {
|
|
let mount_point = VFS
|
|
.resolve_path_absolute(path, VFS.root_inode())
|
|
.await
|
|
.unwrap_or_else(|e| panic!("Could not find automount path: {}. {e}", path.as_str()));
|
|
|
|
VFS.mount(mount_point, fs, None)
|
|
.await
|
|
.unwrap_or_else(|e| panic!("Automount failed: {e}"));
|
|
}
|
|
|
|
let inode = VFS
|
|
.resolve_path_absolute(&init, VFS.root_inode())
|
|
.await
|
|
.expect("Unable to find init");
|
|
|
|
let task = current_task_shared();
|
|
|
|
// Ensure that the exec() call applies to init.
|
|
assert!(task.process.tgid.is_init());
|
|
|
|
// Now that the root fs has been mounted, set the real root inode as the
|
|
// cwd and root.
|
|
*task.cwd.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
|
|
*task.root.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
|
|
|
|
let console = VFS
|
|
.open(
|
|
Path::new("/dev/console"),
|
|
OpenFlags::O_RDWR,
|
|
VFS.root_inode(),
|
|
FilePermissions::empty(),
|
|
&task,
|
|
)
|
|
.await
|
|
.expect("Could not open console for init process");
|
|
|
|
{
|
|
let mut fd_table = task.fd_table.lock_save_irq();
|
|
|
|
// stdin, stdout, stderr
|
|
fd_table
|
|
.insert(console.clone())
|
|
.expect("Could not clone FD");
|
|
fd_table
|
|
.insert(console.clone())
|
|
.expect("Could not clone FD");
|
|
fd_table
|
|
.insert(console.clone())
|
|
.expect("Could not clone FD");
|
|
}
|
|
|
|
drop(task);
|
|
|
|
process::exec::kernel_exec(inode, vec![init.as_str().to_string()], vec![])
|
|
.await
|
|
.expect("Could not launch init process");
|
|
}
|
|
|
|
struct KOptions {
|
|
init: Option<PathBuf>,
|
|
root_fs: Option<String>,
|
|
automounts: Vec<(PathBuf, String)>,
|
|
}
|
|
|
|
fn parse_args(args: &str) -> KOptions {
|
|
let mut kopts = KOptions {
|
|
init: None,
|
|
root_fs: None,
|
|
automounts: Vec::new(),
|
|
};
|
|
|
|
let mut opts = Options::new(args.split(" "));
|
|
|
|
loop {
|
|
match opts.next_opt() {
|
|
Ok(Some(arg)) => match arg {
|
|
Opt::Long("init") => kopts.init = Some(PathBuf::from(opts.value().unwrap())),
|
|
Opt::Long("rootfs") => kopts.root_fs = Some(opts.value().unwrap().to_string()),
|
|
Opt::Long("automount") => {
|
|
let string = opts.value().unwrap();
|
|
let mut split = string.split(",");
|
|
let path = split.next().unwrap();
|
|
let fs = split.next().unwrap();
|
|
|
|
kopts.automounts.push((PathBuf::from(path), fs.to_string()));
|
|
}
|
|
Opt::Long(x) => warn!("Unknown option {}", x),
|
|
Opt::Short(x) => warn!("Unknown option {}", x),
|
|
},
|
|
Ok(None) => return kopts,
|
|
Err(e) => error!("Could not parse option: {}, ignoring.", e),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn kmain(args: String, ctx_frame: *mut UserCtx) {
|
|
sched_init();
|
|
|
|
register_fs_drivers();
|
|
|
|
let kopts = parse_args(&args);
|
|
|
|
spawn_kernel_work(launch_init(kopts));
|
|
|
|
dispatch_userspace_task(ctx_frame)
|
|
}
|