Skip to main content

kernel/sched/
spawn.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Spawn new processes
3//!
4//! Authors: MarioS271
5
6use crate::mm::mm_error::MmError;
7use crate::mm::vmm::address_space::AddressSpace;
8use crate::sched::loader::defs::error::ElfError;
9use crate::sched::loader::load::{map_phdrs_and_copy_elf, setup_user_stack};
10use crate::sched::loader::validate::validate_elf;
11use crate::sched::process::{Pid, Process};
12use crate::state::kstate::KSTATE;
13
14/// Wrapper type for `Result<T, SpawnError>`
15pub type SpawnResult<T> = Result<T, SpawnError>;
16
17/// Indicates an error when attempting to spawn a new process
18pub enum SpawnError {
19    InvalidBinary,
20    OutOfMemory,
21    MappingCollision
22}
23impl From<MmError> for SpawnError {
24    /// Convert a given [`MmError`] into a [`SpawnError`]
25    fn from(value: MmError) -> Self {
26        match value {
27            MmError::MisalignedAddress | MmError::NotFound => Self::InvalidBinary,
28            MmError::OutOfMemory => Self::OutOfMemory,
29            MmError::Overlap => Self::MappingCollision
30        }
31    }
32}
33impl From<ElfError> for SpawnError {
34    /// Convert a given [`ElfError`] into a [`SpawnError`]
35    fn from(_: ElfError) -> Self {
36        Self::InvalidBinary
37    }
38}
39
40/// Spawn a new process, returning its PID
41///
42/// # Safety
43/// The caller must guarantee that this method is only called after boot stage 2 has completed
44pub unsafe fn spawn_from_elf(elf: &[u8], parent_pid: Pid) -> SpawnResult<Pid> {
45    let (phdrs, e_entry) = validate_elf(elf)?;
46
47    let mut addr_space = unsafe { AddressSpace::new_user_addr_space() };
48    map_phdrs_and_copy_elf(&mut addr_space, phdrs, elf)?;
49
50    let user_stack_top = setup_user_stack(&mut addr_space)?;
51    let kernel_stack_top = unsafe {
52        crate::mm::kernel::alloc_stack(&mut KSTATE.mm.pmm().lock(), &mut KSTATE.mm.kernel_addr_space().lock())
53    }?;
54
55    let pid = KSTATE.sched.alloc_pid();
56
57    let mut process = Process::new(
58        pid,
59        parent_pid,
60        addr_space,
61        kernel_stack_top
62    );
63    process.regs.rip = e_entry;
64    process.regs.rsp = user_stack_top.as_u64();
65
66    unsafe { KSTATE.sched.insert_process(process) };
67
68    Ok(pid)
69}
70
71// TODO: enter_process