diff --git a/crates/mem/src/vm.rs b/crates/mem/src/vm.rs index 41729392..6ffaf351 100644 --- a/crates/mem/src/vm.rs +++ b/crates/mem/src/vm.rs @@ -209,7 +209,7 @@ impl VmInjectFillAction for VmFillAction { fn requests_all_pages_filled(&self, parent_object: &VmObject) -> bool { match self { VmFillAction::Nothing => false, - VmFillAction::Scrub(_) => true, + VmFillAction::Scrub(_) => false, VmFillAction::InjectWith(rw_lock) => { rw_lock.read().requests_all_pages_filled(parent_object) } diff --git a/kernel/src/context.rs b/kernel/src/context.rs index 7c31e809..2c0c2fc2 100644 --- a/kernel/src/context.rs +++ b/kernel/src/context.rs @@ -56,6 +56,34 @@ pub struct ProcessContext { pub rsp: u64, } +impl ProcessContext { + pub const fn new() -> Self { + Self { + r15: 0, + r14: 0, + r13: 0, + r12: 0, + r11: 0, + r10: 0, + r9: 0, + r8: 0, + rbp: 0, + rdi: 0, + rsi: 0, + rdx: 0, + rcx: 0, + rbx: 0, + rax: 0, + cs: 0, + ss: 0, + rflag: 0, + rip: 0, + exception_code: 0, + rsp: 0, + } + } +} + pub static mut KERNEL_RSP_PTR: u64 = 0x200000000000; pub static mut USERSPACE_RSP_PTR: u64 = 0x121212; @@ -194,30 +222,7 @@ pub unsafe extern "C" fn userspace_entry(context: *const ProcessContext) { } pub unsafe fn context_of_caller() -> ProcessContext { - let mut pc = ProcessContext { - r15: 0, - r14: 0, - r13: 0, - r12: 0, - r11: 0, - r10: 0, - r9: 0, - r8: 0, - rbp: 0, - rdi: 0, - rsi: 0, - rdx: 0, - rcx: 0, - rbx: 0, - rax: 0, - cs: 0, - ss: 0, - rflag: 0, - rip: 0, - exception_code: 0, - rsp: 0, - }; - + let mut pc = ProcessContext::new(); unsafe { asm!( " diff --git a/kernel/src/process.rs b/kernel/src/process.rs index 7675d3a5..5ec73e68 100644 --- a/kernel/src/process.rs +++ b/kernel/src/process.rs @@ -23,14 +23,17 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +use arch::{CpuPrivilege, registers::Segment}; use elf::{ElfErrorKind, elf_owned::ElfOwned}; use mem::{ addr::VirtAddr, paging::{PageTableLoadingError, Virt2PhysMapping, VmPermissions}, - vm::{InsertVmObjectError, VmFillAction, VmProcess, VmRegion}, + vm::{InsertVmObjectError, PageFaultInfo, PageFaultReponse, VmFillAction, VmProcess, VmRegion}, }; use vm_elf::VmElfInject; +use crate::context::{ProcessContext, userspace_entry}; + pub mod vm_elf; /// A structure repr a running process on the system @@ -38,6 +41,7 @@ pub mod vm_elf; pub struct Process { vm: VmProcess, id: usize, + context: ProcessContext, } /// A structure repr the errors that could happen with a process @@ -54,14 +58,20 @@ pub enum ProcessError { /// This flag tells you if the assertion was to have the table loaded (true) /// or unloaded (false). LoadedAssertionError(bool), + /// The process should never return from the enter userspace function + ProcessShouldNotExit, } impl Process { + /// This is the start address that processes should base their stack from + const PROCESS_STACK_START_ADDR: VirtAddr = VirtAddr::new(0x7fff00000000); + /// Create a new empty process pub fn new(id: usize, table: &Virt2PhysMapping) -> Self { Self { vm: VmProcess::inhearit_page_tables(table), id, + context: ProcessContext::new(), } } @@ -76,25 +86,10 @@ impl Process { } } - /// Asserts that this process should be the currently loaded process to do - /// the requested action. For example, when populating this processes pages - /// it needs to be activly loaded. - pub fn assert_loaded(&self, should_be_loaded: bool) -> Result<(), ProcessError> { - if self.vm.page_tables.is_loaded() == should_be_loaded { - Ok(()) - } else { - Err(ProcessError::LoadedAssertionError(should_be_loaded)) - } - } - /// Add an elf to process's memory map pub fn add_elf(&self, elf: ElfOwned) -> Result<(), ProcessError> { - // Page tables need to be loaded before we can map the elf into memory - self.assert_loaded(true)?; - let (start, end) = elf.elf().vaddr_range().unwrap(); - let elf_object = VmElfInject::new(elf); - let inject_el = VmFillAction::convert(elf_object); + let inject_el = VmFillAction::convert(VmElfInject::new(elf)); self.vm .inplace_new_vmobject( @@ -111,19 +106,45 @@ impl Process { Ok(()) } + /// Init the process's context structure + pub fn init_context(&mut self, entry: VirtAddr, stack: VirtAddr) { + self.context = ProcessContext::new(); + self.context.ss = Segment::new(4, CpuPrivilege::Ring3).0 as u64; + self.context.cs = Segment::new(5, CpuPrivilege::Ring3).0 as u64; + self.context.rip = entry.addr() as u64; + self.context.rsp = stack.addr() as u64; + } + /// Map an anon zeroed scrubbed region to this local process pub fn add_anon( &self, region: VmRegion, permissions: VmPermissions, ) -> Result<(), ProcessError> { - // Page tables need to be loaded before we can map the elf into memory - self.assert_loaded(true)?; - self.vm .inplace_new_vmobject(region, permissions, VmFillAction::Scrub(0)) .map_err(|err| ProcessError::InsertVmObjectErr(err))?; Ok(()) } + + /// Make a new process with elf + pub fn exec(elf: ElfOwned) -> Result<(), ProcessError> { + todo!() + } + + /// This process's page fault handler + pub fn page_fault_handler(&self, info: PageFaultInfo) -> PageFaultReponse { + self.vm.page_fault_handler(info) + } + + /// Context switch into this process + pub unsafe fn switch_into(&self) -> Result<(), ProcessError> { + if !self.vm.page_tables.is_loaded() { + return Err(ProcessError::LoadedAssertionError(true)); + } + + unsafe { userspace_entry(&raw const self.context) }; + Err(ProcessError::ProcessShouldNotExit) + } } diff --git a/kernel/src/process/vm_elf.rs b/kernel/src/process/vm_elf.rs index 2e8c99f5..5c9125b3 100644 --- a/kernel/src/process/vm_elf.rs +++ b/kernel/src/process/vm_elf.rs @@ -130,10 +130,6 @@ impl VmElfInject { } impl VmInjectFillAction for VmElfInject { - fn requests_all_pages_filled(&self, _parent_object: &mem::vm::VmObject) -> bool { - true - } - /// Put data into this page fn populate_page( &mut self,