diff --git a/kernel/proc.c b/kernel/proc.c index b1d1a4b..1db2abc 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -56,47 +56,7 @@ procinit(void) // If found, initialize state required to run in the kernel, // and return with p->lock held. // If there are no free procs, or a memory allocation fails, return 0. -struct proc* allocproc(void) -{ - struct proc *p; - - for(p = proc; p < &proc[NPROC]; p++) { - acquire(&p->lock); - if(p->state == UNUSED) { - goto found; - } else { - release(&p->lock); - } - } - return 0; - -found: - p->pid = allocpid(); - p->state = USED; - - // Allocate a trapframe page. - if((p->trapframe = (struct trapframe *)kalloc()) == 0){ - freeproc(p); - release(&p->lock); - return 0; - } - - // An empty user page table. - p->pagetable = proc_pagetable(p); - if(p->pagetable == 0){ - freeproc(p); - release(&p->lock); - return 0; - } - - // Set up new context to start executing at forkret, - // which returns to user space. - memset(&p->context, 0, sizeof(p->context)); - p->context.ra = (uint64)forkret; - p->context.sp = p->kstack + PGSIZE; - - return p; -} +struct proc *allocproc(void); // Create a user page table for a given process, with no user memory, // but with trampoline and trapframe pages. diff --git a/kernel/rustkernel/src/proc/process.rs b/kernel/rustkernel/src/proc/process.rs index a0a281e..0b77e11 100644 --- a/kernel/rustkernel/src/proc/process.rs +++ b/kernel/rustkernel/src/proc/process.rs @@ -2,9 +2,9 @@ use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe}; use crate::{ - arch::riscv::{Pagetable, PTE_W}, + arch::riscv::{Pagetable, PTE_W, PGSIZE}, fs::file::{File, Inode}, - mem::kalloc::kfree, + mem::{kalloc::{kfree, kalloc}, memset}, sync::spinlock::Spinlock, }; use core::{ @@ -36,7 +36,7 @@ extern "C" { pub fn proc_mapstacks(kpgtbl: Pagetable); pub fn proc_pagetable(p: *mut Process) -> Pagetable; pub fn proc_freepagetable(pagetable: Pagetable, sz: u64); - pub fn allocproc() -> *mut Process; + // pub fn allocproc() -> *mut Process; pub fn uvmalloc(pagetable: Pagetable, oldsz: u64, newsz: u64, xperm: i32) -> u64; pub fn uvmdealloc(pagetable: Pagetable, oldsz: u64, newsz: u64) -> u64; } @@ -57,6 +57,7 @@ pub enum ProcessState { #[derive(Copy, Clone, Debug, PartialEq)] pub enum ProcessError { + MaxProcesses, Allocation, } @@ -132,6 +133,53 @@ impl Process { pub fn alloc_pid() -> i32 { NEXT_PID.fetch_add(1, Ordering::SeqCst) } + /// Look in the process table for an UNUSED proc. + /// If found, initialize state required to run in the kernel, + /// and return with p.lock held. + /// If there are no free procs, or a memory allocation fails, return an error. + pub unsafe fn alloc() -> Result<&'static mut Process, ProcessError> { + let mut index: Option = None; + for (i, p) in &mut proc.iter_mut().enumerate() { + p.lock.lock_unguarded(); + if p.state == ProcessState::Unused { + index = Some(i); + break; + } else { + p.lock.unlock(); + } + } + let Some(index) = index else { + return Err(ProcessError::MaxProcesses); + }; + + let p: &mut Process = &mut proc[index]; + p.pid = Process::alloc_pid(); + p.state = ProcessState::Used; + + // Allocate a trapframe page. + p.trapframe = kalloc() as *mut Trapframe; + if p.trapframe.is_null() { + p.free(); + p.lock.unlock(); + return Err(ProcessError::Allocation); + } + + // An empty user page table. + p.pagetable = proc_pagetable(addr_of_mut!(*p)); + if p.pagetable.is_null() { + p.free(); + p.lock.unlock(); + return Err(ProcessError::Allocation); + } + + // Set up new context to start executing at forkret, + // which returns to userspace. + memset(addr_of_mut!(p.context).cast(), 0, core::mem::size_of::() as u32); + p.context.ra = forkret as usize as u64; + p.context.sp = p.kstack + PGSIZE; + + Ok(p) + } /// Free a proc structure and the data hanging from it, including user pages. /// self.lock must be held. @@ -223,6 +271,15 @@ pub extern "C" fn allocpid() -> i32 { Process::alloc_pid() } +#[no_mangle] +pub unsafe extern "C" fn allocproc() -> *mut Process { + if let Ok(process) = Process::alloc() { + process as *mut Process + } else { + null_mut() + } +} + /// Free a proc structure and the data hanging from it, including user pages. /// p->lock must be held. #[no_mangle]